Polyray v1.5

Copyright (c) 1991, 1992 Alexander R. Enzmann

8 Noviembre 1992

Todos Derechos Reservados

Traduccido por M. A. Díaz Mariscal Febrero 1994

Tabla de contenidos

1. Información de Introducción y Shareware	5

1.1. Origen y Créditos	6

1.2. Herramientas útiles	7

1.3. Contenidos de Este Documento	7

1.4. Demostración Rápida (Deberia leer esta sección)	8

1.5. Opciones de Línea de Comandos	11

1.6. Archivo de Inicialización	12

1.7. Produciendo Escenas	14

1.7.1. Rastreando (Raytracing)	14

1.7.1.1. Antiescalonamiento (Antialiasing)	14

1.7.1.2. Difuminando (Dithering)	15

1.7.1.3. Marcando Límites	16

1.7.1.4. Flags de Sombreado	17

1.7.2. Conversión de polígonos (Scan Conversion)	18

1.7.3. Modelo Inalambrico (Wireframe)	19

2. Detallada Descripción del Formato de Entrada de Polyray	19

2.1. Expresiones	19

2.1.1. Expresiones Numéricas	20

2.1.2. Expresiones Vectoriales	21

2.1.3. Expresiones Matriciales	22

2.1.4. Expresiones Condicionales	24

2.1.5. Expresiones en tiempo de ejecución	25

2.1.6. Etiquetas	25

2.2. Definición de punto de vista	26

2.3. Objetos/Superfícies	28

2.3.1 Modificadores de objetos	30

2.3.1.1. Modificadores de posición y orientación	30

2.3.1.1.1. Traslación	30

2.3.1.1.2. Rotación	30

2.3.1.1.3. Escala	31

2.3.1.1.4. Recortes	31

2.3.1.2. Cajas de Límites	32

2.3.1.3. Subdivisión de Objetos	32

2.3.1.4. Banderas de Sombreando	33

2.3.2. Objetos	33

2.3.2.1. Superficies de Bezier	34

2.3.2.2. Burbujas	35

2.3.2.3. Cajas	37

2.3.2.4. Conos	38

2.3.2.5. Cilindros	38

2.3.2.6. Discos	39

2.3.2.7. Superficies Implícitas	39

2.3.2.8. Campos de Elevación (Height Fileds)	40

2.3.2.8.1. Campos de Elevación basados en ficheros	41

2.3.2.8.1.1. Formato de 8 bit	41

2.3.2.8.1.2. Formato de 16 bit	42

2.3.2.8.1.3. Formato de 24 bit	42

2.3.2.8.2. Campos de Elevación Implícitos	43

2.3.2.9. Superficies de Lathe	44

2.3.2.10. Parábolas	45

2.3.2.11. Polígonos	45

2.3.2.12. Superficies Polinomiales	46

2.3.2.13. Esferas	48

2.3.2.14. Superficies de barrido	48

2.3.2.15. Anillos Toroidales	49

2.3.2.16. Superficies Triangulares	50

2.3.3. Geometría Del Espacio Constructiva (CSG)	50

2.3.4. Objetos enrejados (Gridded Objects)	52

2.3.5. Marcando Límites	53

2.4. Color e Iluminación	53

2.4.1. Fuentes de Luz	54

2.4.1.1. Luces Posicionales	54

2.4.1.2. Luces Zonales (Spot Lights)	54

2.4.1.3. Luces con Texturas	55

2.4.2. Color de Fondo	55

2.4.3. Texturas	56

2.4.3.1. Procedimientos de Texturas	56

2.4.3.1.1. Modelo de sombreado estándar	56

2.4.3.1.1.1. Luz ambiental	58

2.4.3.1.1.2. Luz Difusa	58

2.4.3.1.1.3. Brillos especulares	58

2.4.3.1.1.4. Reflexiones	59

2.4.3.1.1.5. Transmisión de luz	59

2.4.3.1.1.6. Distribución de microfacetas (Microfacet)	60

2.4.3.1.2. Texturas de tipo "checker"	6060

2.4.3.1.3. Texturas Hexagonales	61

2.4.3.1.4. Superfícies de ruido	62

2.4.3.1.5. Texturas estratificadas	65

2.4.3.2. Texturas funcionales	67

2.4.3.2.1. Mapas de Imágenes	69

2.5. Comentarios	71

2.6. Apoyo de Animación	71

2.7. Procesamiento Condicional	72

2.8. Inclusión de archivos	73

2.9. Flujo de archivos	73

3. Formatos de Archivo	74

3.1 Archivos de salida	74

4. Algoritmos	74

4.1. Procesando expresiones polinomiales	74

4.1.1. Ejemplo de una ecuación de representación	75

4.1.2. Sintaxis de Fórmulas permitidas	75

4.1.3. Reglas para procesar fórmulas	76

4.2. Procesando superficies funcionales arbitrarias	77

4.2.1. Coordenadas esféricas	77

4.3. Generación de ruido Tridimensional	78

4.4. El algoritmo "Marching Cubes"	79

5. Notas del traductor	80

1. Información de Introducción y Shareware

El programa "polyray" es un trazador de rayos {raytracer} capaz de interpretar (render) una gran variedad de formas y superficies, desde primitivas de cajas, esferas, etc., a expresiones de polinomios de tres variables, así como superficies que pueden contener funciones trascendentales como senos, cosenos y logaritmos (son las más lentas de interpretar). Los archivos asociados con Polyray están distribuidos en tres partes: el ejecutable, una colección de documentos, y un conjunto de ficheros de datos.

Polyray es un programa shareware. Si disfruta de este programa, y lo utiliza frecuentemente, y puede pagar unos honorarios de registro, entonces envíe 35 dólares a:

Alexander Enzman

20 Clinton St.

Woburn, Ma 01801

U.S.A.

Por favor incluya su nombre y Dirección.

Si registra formalmente este programa, recibirá la siguiente release de Polyray gratuítamente. Además contribuirá a mi habilidad para comprar herramientas de software para hacer de Polyray un programa mejor. Si no registrara este programa, no se sienta mal - yo Soy pobre también- pero no debería esperar recibir respuestas a preguntas o errores. Observe que tanto los ejecutables como los documentos de Polyray están protegidos por derechos de autor. Los ficheros de datos son de domínio público, así que usted puede utilizalos de la manera que mejor le plazca.

Si quiere un libro de referencia bueno acerca de trazadores de rayos {raytracing}, sería recomendable adquirir el libro: "Introducing to Raytracing", editada por Andrew Glassner, Academic Press, 1989. Ese libro es excelente y proveerá muchos de los detalles que no están contenidos en este manual. Para una lista abreviada de la sintaxis de Polyray, vea el archivo quickref.txt.

Este documento contiene una descripción paso a paso de un archivo de escena simple para hacerle familiar con la estructura de información de Polyray. Trabajando a través de un ejemplo y revisando otros ejemplos en el archivo de información, debería ser capaz de ver como los diversos caracteres distintivos están siendo utilizados.

Los ficheros de datos son texto ASCII, los formatos de fichero de imagen son Targa (vea la sección 3.1 para los formatos soportados de entrada y de salida). Es inprobable que se soporten otros formatos gráficos. El formato de Targa está soportado por muchos programas de proceso de imágenes así si necesita traducir entre Targa y algún otro formato la cosa es bastante simple. (Al utilizar este formato no tuve que definir el mio propio y de esa forma tambiém me quite de encima la construcción de programas de conversión o convercer a otros para que los construyan.)

El único modo de muestra es el estándar 320x200 modo de color de VGA. Intenté en un principio realizar el código para las SVGA, pero como existen una gran variedad, esto sería bastante engorroso. Por esta razón, la muestra para Polyray deberia estar considerada como una ayuda durante la depuración de imágenes, y cómo un modo de monitorear el estado que estamos produciendo. Para observar la imagen final, hay muchos proramas de visualización de imagenes y muchos programas de conversión de formato que transformará los TGA a al formato que prefirieramos (PICLAB podría ser uno de los mejores para trabajos de aplicación general).

El estándar ejecutable requiere un IBM PC compatible con al menos un 386 y 387, gráficos VGA, y un mínimo de 2 Mbytes de RAM para funcionar. Realizaré otros modelos de memoria si hay disponibles suficientes solicitudes. El ejecutable distribuido utiliza una extensión del DOS para obtenrer tanta memoria como sea posible. Ha sido exitosamente ejecutada tanto con HIMEM.SYS, como 386MAX.SYS. Bajo Windows funcionará como una ventana DOS, sin embargo si utilizamos el display gráfico, necesitaremos entonces funcionar en modo pantalla completa.

Estoy interesado en cualquier informe de comentario/error. Puedo ser localizado mediante correo electrónco {email} por:

Compuserve como: Alexander Enzmann 70323,2461

Internet como: xander@mitre.org

o a través del servicio postal en:

Alexander Enzmann

20 Clinton St.

Woburn, Ma 01801

USA

1.1 Origen y Créditos

El código original de este programa fue basado en el "mtv" trazador de rayos, escrito (y situado bajo dominio público) por Mark Vandewettering. Muchas gracias a David Mason por sus numerosos comentarios y sugerencias (y por añadir una nueva característica al DTA cada vez que necesité probar algo).

1.2 Herramientas útiles

Hay varios tipos de herramientas que usted querrá tener para trabajar coneste programa (en orden relativa de importancia):

• Un editor de texto ASCII para preparar y modificar archivos de entrada.

• Un visualizador de imagenes para observar las imágenes obtenidas.

• Un programa de procesamiento de imagen para traducción entre Targa y algunos otros formatos.

• Un generador de animación que tomará una serie de imágenes TGA y formará un archivo de animación.

• Un visualizador de animaciones para ver la aimación en la pantalla.

Para el mundo de los PC's (que es lo qué utilizo en casa), hay varios programas populares y fácilmente disponibles: "PICLAB", que puede leer, procesar y escribir a varios formatos gráficos populares, "VPIC" (shareware) que presenta imágenes rápidamente y sostiene una gran variedad de formatos de video, "DTA" que tomará un racimo de ficheros Targa y producirá un archivo de animación de formato "fli", y "AAPLAY" o "PLAY80" que mostrarán un FLI en una pantalla VGA.

1.3 Contenidos de este documento

Este documento describe el formato y capacidades de entrada del "polyray" programa de rastreo de rayos. En Ployray podemos disfrutar de las siguientes funciones:

Definición del Punto de vista (cámara).

Luces de Posición (punto), direccionales (reflector), y funcionales (texturadas).

El color de fondo.

Definción de la Superficie de los objetos.

Primitivas:

Superficies de Bezier, burbujas, cajas, conos, cilindros, discos, funciones implícitas, campos de elevación, superficies de Lathe, parábolas, polígonos, funciones polinomiales, esferas, superficies de barrido, anillos toroidales, superficies triangulares.

Soporte de Animación.

Procesamiento Condicional.

Inclusión de archivos.

Declaración de valores y objetos.

Geometría Del Espacio Constructiva (CSG).

Cuadriculado de objetos.

Texturas definibles por el Usuario (funcionales).

Archivo de Inicialización para valores por omisión.

1.4 Demostración Rápida

Esta sección describe uno de los ficheros de datos posibles más simples: una esfera única y una fuente de luz única. Todo lo que sigue a un doble // es un comentario y será ignorado por Polyray (Debido a que Polyray usa como Parsec el YACC no deberemos utilizar en ninguna parte del código valores ASCII superiores al 126, o sea, nada ce acentos ni de "ñ" en los comentarios. N.T.). El fichero de datos son las siguientes líneas indentadas. Usted puede utilizar el archivo "esfera.pi", o copiar estas declaraciones en un nuevo archivo.

// Comenzamos estableciendo la cámara. Esto es donde el ojo

// está localizado, y describe cuanta anchura del campo visual

// será usada, y la resolución (# de pixels de ancho y alto)

// de la imagen resultante.

viewpoint

{

from <0,0,8>	// La ubicación del ojo

at <0,0,0>	// El punto al que estamos mirando

up <0,1,0>	// La dirección del techo

angle 45	// El campo visual vertical

resolution 160, 160	// La imagen sera de 160x160 pixels

}

// A continuación se define el color del fondo. Este es el color que será utilizado

// por cualquier pixel que no sea parte de un objeto. En este archivo aparecerá

// el color alrededor de la esfera.

background skyblue

// Después es una fuente de luz. Esta es una fuente de luz puntual

// un poco retrasada, a la izquierda, y detrás del ojo.

light <-10,3,-20>

// la Siguiente declaración es una textura que será aplicada a la esfera.

// Será roja en cada punto pero donde la luz se refleje directamente hacia el ojo -

// en ese punto habrá un lugar blanco brillante.

define shiny_red

texture

{

surface

{

ambient red, 0.2	// Siempre un poco rojo

diffuse red, 0.4	// Donde la luz está

// golpeando la esfera, el

// color será un poco más

// brillante.

specular white, 0.8	// Un destaque blanco.

microfacet Reitz 10	// Las gotas de destaque a

// mitad de su intensidad en

// un ángulo de 10 grados.

}

}

// Finalmente declaramos la esfera. Se situa en el origen, y tiene un radio de dos

// unidades. Siguiendo la declaración de la esfera, asociamos la textura declarada

// anteriormente.

object

{

sphere <0, 0, 0>, 2

shiny_red

}

Ahora que tenemos un fichero de datos, convirtamoslo y mostremoslo en la pantalla. Ante todo podemos mirar una representación mediante líneas (wireframe - modelo inhalambrico). Teclee los siguientes comandos (los prompts del DOS están en mayúsculas).

C> polyray esfera.pi -r 2 -V 1 -W

Un esbozo de la esfera serán aproximado en la pantalla, prensionar cualquier tecla para salir al DOS.

Después convirtamoslo. Entrar lo siguiente:

C> polyray esfera.pi -V 1

La esfera será dibujada línea a línea, cuando finalize retornaremos al DOS.

La imagen de salida serán el archivo de salida de valor por omisión, "out.tga". Se puede ver directamente con VPIC O TGVIEW (aunque VPIC no tendrá el rango completo de colores que generados por el raytracer). Si tuvieramos PICLAB, entonces los siguientes comandos cargarán la imagen y proyectarán sus colores en un espectro que coincide con los colores de la imagen.

C> piclab

> tload out

> makepal

> map

> show

hit nay key to get back to PICLAB's command line

> quit

C>

La imagen mostrada sería la siguiente:

Deberíamos ver una imagen sustancialmente mejorada sobre la mostrada durante el proceso de rastreo. Ahora que ha visto una imagen simple, tiene dos opciones: tracear uno o todos los ficheros en el archivo de datos, o continuar leyendo los documentos. Si prefiere comenzar rápidamente, hay una serie de archivos BATCH del DOS que automatizan bastante bien la producción de las escenas de ejemplos. (Cuando descomprima los ficheros de datos, recuerde utilizar el conmutador /d, de modo que se creen todos los subdirectorios.)

1.5 Opciones de Línea de Comandos.

Un serie de operaciones pueden ser realizadas bien a través de los valores de un archivo de inicialización, bien dentro del fichero de datos, bien a través de la línea de mandatos (el procesado se realiza en ese orden, teniendo más prioridad la última lectura). Los posibles valores que se pueden pasar en la línea de mandatos se mostrarán en el casp de no existir argumentos al llamar a Polyray.

Los valores que pueden ser especificados en la línea de comandos, con una descripción breve de su significado son:

-a	Desempeña un antiescalonamiento simple {antialiasing} (la media de los pixels vecinos).

-A	Desempeña un antiescalonamiento adaptable (basado en umbrales).

-b pixels	Establecen el número máximo de pixels que serán calculados entre niveles de archivo.

-B	Envía la salida al archivo para cada línea que se ha escaneado.

-d probabilidad	Difuminación de los objetos (dither = temblor) utilizando la probabilidad dada.

-D escala	Difuminar todos los rayos utilizando la probabilidad dada.

-J	Desempeña otro tipo de antiescalonamiento (jittered) mezclando el número de muestras/pixel.

-o Nom. fichero	El nombre del archivo de salida. El nombre del archivo de salida de por defecto si no se especificara es "out.tga".

-p bits/pixel	Posiciona el número de bits por pixel en el archivo de salida (tiene que ser uno de los siguientes 8, 16, 24, 32).

-P paleta	Que opción de paleta utilizará [0=gris, 1=666, 2=884].

-q flags	Habilitar/Desabilitar diversas opciones de sombreado globales.

-Q	Aborta si se pulsa una tecla durante el rastreo.

-r renderer	Que método de rastreo: [0=raytrace, 1=scan_convert, 2=wireframe]. (Sucesivamente: Traceo de rayos, conversion de polígonos mediante z-buffer o modelo inhalabrico)

-R	Reinicia un rastreo interrumpido.

-s muestras	# de muestras por pixel cuando se ejecuta el antiescalonamiento {antialiasing}.

-t status_vals	Tipo de salida de estado [0=ninguno, 1=totales, 2=línea, 3=pixel].

-T umbral	Umbral para comenzar el sobremuestreo {oversampling}.

-u	Escribe al archivo de salida en forma descomprimida.

-v	Rastrea de abajo a arriba.

-V modo	Usa la VGA mientras se rastrea [0=ninguno, 1=VGA]

-W	Espera la pulsación de una tecla antes de limpiar la pantalla.

-x columnas	Establecer la resolución horizontal.

-y líneas	Establecer la resolución vertical.

-z start_line	Comienza el rastreo en una línea especificada.

Si no existieran argumentos, entonces Polyray nos dará un resumen de la descripción de las opciones de línea de comandos.

1.6 Archivo de Inicialización

La primera operación llevada a cabo por Polyray es leer el archivo de inicialización "polyray.ini". Este archivo puede se utilizado para inicializar las variables por omisión utilizadas durante el rastreo. Este archivo tiene que aparecer en el directorio en cursol. Este archivo no tiene que existir, es utilizado típicamente como una conveniencia para eliminar los parámetros de línea de mandatos.

Cada entrada en el archivo de inicialización tiene que aparecer en una línea separada, y tener la forma:

default_name	valor

Los nombres son texto. Los valores son numéricos para algunos nombres, y texto para otros. Los nombres y valores permitidos son:

abort_test	true/false/on/off

alias_threshold	[valor mínimo para comenzar el antiescalonamiento adaptable {antialiasing}]

antialias	none / filter / jitter / adaptive (ninguno / filtro / intranquiliza / adaptable)

display	none/vga

max_level	[máxima profundidad de recursión]

max_lights	[máximo # de luces]

max_queue_size	[máximo # de objetos en una cola de prioridad]

max_samples	[ # de muestras para el antiescalonamiento {antialiasing}]

pixel_size	[ 8, 16, 24, 32]

pixel_encoding	none/rle

renderer	ray_trace/scan_convert/wire_frame

shade_flags	[default/máscara de bits de los flags, ver sec 1.7.1.4.]

shadow_tolerance	[distancia mínima para objetos bloqueadores]

status	none/totals/line/pixel

warnigs	on/off

Un ejemplo típico de "polyray.ini" sería:

abort_test	off

alias_threshold	0.05

antialias	adaptive

display	vga

max_samples	8

pixel_size	24

status	line

Si no existiera el archivo de inicialización, entonces Polyray utilizará los siguientes valores por omisión:

abort_test	on

alias_threshold	0.2

antialias	none

display	none

max_level	5

max_lights	64

max_queue_size	128

max_samples	4

pixel_size	16

pixel_encoding	rle

renderer	ray_trace

shade_flags	default

shadow_tolerance	0.001

status	line

warnings	on

1.7 Produciendo Escenas

Polyray nos ofrece tres alternativas muy distintas para producir escenas: raytracing (traceo de rayos), scan-convert (conversión de polígonos mediante el z-buffer), y el wireframe (modelo inhalambrico). El Raytracing es un proceso muy lento, sin embargo se pueden producir ciertos tipos de superficies con esta técnica que son muy difíciles por no decir imposibles de conseguir utilizando técnicas tradicionales, como la del z-buffer.

1.7.1 Rastreando

Polyray es el corazón de un rastreador de rayos {raytracer}. La calidad de las imágenes que se pueden producir depende totalmente de cuánto tiempo queremos esperar para obtener los resultados. Hay ciertas opciones que permiten ajustar los requisistos de compensación de factores de calidad versus velocidad versus requisitos de memoria.

La operación básica en el rastreo es el de disparar un rayo desde el ojo, a través de un pixel, y golpeando finalmente un objeto. Por cada tipo de objeto hay un código especializado que ayuda a determinar si el rayo ha golpeado o no dicho objeto. El modo estándar que Polyray utiliza para generar una imagen es utilizar un rayo por pixel y probar ese rayo contra todos los objetos existentes en el fichero de datos.

Las siguientes secciones describen como podemos hacer que Polyray utilice más rayos por pixel para mejorar la calidad de la imagen, omitir pixels u objetos en un modo probabilístico de mejorar la velocidad, o particionar objetos de tal manera que no exista la necesidad de probar todos los objetos para cada rayo. Cada una de estas técnicas tienen beneficios e inconvenientes.

1.7.1.1 Antiescalonamiento

La representación de rayos es como uno una línea dimensional. Por otra parte los pixels y los objetos tienen un tamaño definido. Esto puede llevarnos a un problema conocido como escalonamiento "aliasing", donde un rayo puede no interseccionar un objeto debido a que el objeto sólo recubre parcialmente un pixel; o el pixel deberia tener un color constituido por varios objetos que lo superpone, ninguno de los cuales llena completamente el pixel. El escalonamiento frecuentemente se aparece como un efecto de escalinata en los bordes de los objetos.

Polyray ofrece tres modos para reducir el escalonamiento {aliasing}: por filtrado, por sobremuestreo {oversampling} con determinado número de muestras, y por un sobremuestreo adaptable. El proceso de filtrando suaviza la imagen de salida mediate la media de los valores del color de los pixels vecinos al pixel que se produce. El sobre muestreo se realiza añadiendo rayos extras a través de un proceso aleatorio en la dirección del rayo dentro del pixel que se rastrea. El resultado de todos los rayos que son disparados a través de un pixel único que dan como resultado efectos de escalinata pueden ser reducidos mediante la media o proceso de tanteos.

El proceso de filtrado añade un poco de sobrecarga al proceso de rastreo, además de producir un ligero degradado en la nitidez de la imagen. El proceso de antiescalonamiento aleatorio aminora la velocidad de rastreo en proporción directa al número de rayos extras, pero resulta en una mejor calidad de la imagen.

El sobremuestreo puede ser desempeñado de dos formas, ya sea utilizando un determinado número de rayos por pixel, o por un antiescalonamieento adaptable. El primero siempre disparará el mismo número de rayos a través de cada pixel, independientemente de la complejidad de imagen. El segundo dispara inicialmente sólo un rayo a través de cada pixel, si el color de un pixel es significativamente diferente a cualquiera de sus vecinos, entonces se disparan rayos adicionales.

Los dos variables de inicialización (y de línea de comandos) que afectarán al desempeño del antiescalonamiento adaptable son "alias_threshold" y "max_samples". La primera es una medida de cuan diferente un pixel tiene que ser respecto a sus vecinos antes que el antiescalonamiento sea realizado. Si un pixel tiene el valor: <r1, g1, b1>, y su vecino tiene el valor <r2, g2, b2> (los valores RGB estan comprendidos entre 0 y 1 inclusive), entonces la "distancia" entre los dos colores es:

Esta es la fórmula Pitagórica estándar para valores especificados en RGB. Si "dist" es mayor que el valor de "alias threshold", entonces se dispararan rayos extras a través del pixel para determinar un color medio para dicho pixel.

Nota: Ejecutando la prueba de distancia en el espacio de RGB puede no ser el mejor modo de determinar cuando se produce el escalonamiento. Las versiones futuras de Polyray puede desempeñar cálculos de distancia en espacio de LABORATORIO.

1.7.1.2 Difuminando (Dithering).

Para acelerar la generación de una imagen (y para producir algunos efectos interesantes), varias opciones de difuminación (Dither significa literalmente vibrar o tiritar pero lo he traducido como difuminar ya que se asemeja más al efecto producido) están disponibles: difuminar todos los rayos, difuminar todos los objetos, y difuminar algunos objetos específicos. Asociada con cada opción existe un valor probabilistico entre 0 y 1. Durante el rastreo, si la opción de difuminación está activada, Polyray genera un número aleatorio entre 0 y 1 y lo compara al valor de probabilidad. Si el número aleatorio es mayor que el valor de probabilidad entonces el rayo o el objeto será ignorado.

La difuminación de rayos es un modo de muestrear la imagen completa de una forma más rápida, por ejemplo si de da un valor de probabilidad de 0.5, entonces solamente la mitad de los rayos serán rastreados a través de la escena. La imagen final será pues degradada en gran medida, sin embargo la cantidad de tiempo tomado para rastrear la escena se reducirá aproximadamente a la mitad.

La difuminación de objetos es un modo de simular transparencia, sin la sobrecarga de generar rayos secundarios durante el proceso de rastreo. También puede ser usado como un efecto óptico interesante - durante una animación, si el valor de probabilidad va disminuyéndose sucesivamente desde 1 a 0, el objeto se irá disolviendo.

Los valores de difuminación negativos así como aquellos por encima de 1.0 no tendrán efecto. La forma bajo la que trabaja el proceso de difuminación es: antes de chequear se comprueba si el rayo actual intersectará un objeto, entonces se generará un número aleatorio entre 0 y 1. Si este número fuera inferior al valor de vibración entonces se realizará el chequeo de la intersección. Si el número aleatorio es mayor que el valor de difuminación entonces Polyray supone que no se produce tal intersección.

Ficheros de ejemplo: dither.pi, bnddithr.pi

1.7.1.3 Marcando Límites.

Para escenas con gran cantidad de objetos pequeños, hay trucos de optimización que pueden sacar ventaja de la distribución de los objetos. Uno fácil de implementar, y que frecuentemente resulta en inmensos ahorros de tiempo es marcar los límites. La idea básica es clasificar todos los objetos a lo largo de una dirección particular. Una vez que este paso clasificador ha sido desempeñado, entonces durante el rastreo, el rayo puede ser chequeado rápidamente a traves de este límite (que suele representar a muchos objetos más que a uno sólo) para ver si existe la necesidad de realizar las pruebas de intersección en el contenido del límite.

Las advertencias más importantes para el uso de esta característica de Polyray son:

Escenas con solamente algunos objetos grandes derivarán en beneficios de velocidad pequeños.

Si hay una gran cantidad de superposiciones en las posiciones de los objetos de la escena, se ganará poca velocidad con el uso de los límites.

Si la dirección de los límites no corresponde a una dirección que ordene fácilmente los objetos, entonces se ganará poca velocidad.

Sin embargo, para ficheros de datos que son generados por otros programas, se encuentran frecuentemente los requisitos para el uso efectivo de los límites unificadores. Por ejemplo, la mayoria de los ficheros de datos generados por los programas SPD serán rastreados más rápidademente con límites unificadores que sin ellos.

1.7.1.4 Flags de Sombreado.

Especificando una serie de bits, diversas opciones de sombreado pueden ser habilitadas o desabilitadas. El valor de cada flag, así como su significado es los siguienete:

1	Shadow_Check	Se generarán sombras.

2	Reflect_Check	Se testearán los reflejos.

4	Transmit_Check	Chequeo para refracciones.

8	Two_Sides	Si está en ON, la iluminación será realizada en ambas caras de una superficie.

16	Cast_Shadow	Determina si un objeto lanza sobras.

32	Primary_Rays	Si está en OFF, entonces los rayos primarios (aquellos del ojo) no son chequeados contra el objeto.

Los valores por omisión de estos flags son:

raytracing	Shadow_Check + Reflect_Check + Transmit_Check + Two_Sides + Cast_Shadow + Primary_Rays (= 63).

scan conversion	Two_Sides (= 8).

wireframe	No Aplicable.

La suposición hecha es que durante el rastreo se desea la más alta calidad, y por consiguiente se realizará cada prueba de sombreado. La suposición para la conversión de polígonos es que estamos intentando rastrear rápidamente, y por lo tanto la mayoria de las opciones de sombreado complejas están deshabilitadas.

Si cualquiera de los flags fuera activado explícitamente y se usara la conversión de poligonos para realizar la escena, entonces para cada pixel que sea exhibido, se efectuará una llamada recursiva al raytracer para determinar el sombreado correcto. Observe que debido al naturaleza de los objetos durante la conversión de poligonos, el sombreado, y especialmente la refracción pueden ser utilizados durante este proceso.

Por ejemplo si quisieramos realizar una conversión de poligonos usando las sombras, deberiamos de realizar lo siguiente:

polyray xxx.pi -r 1 -q 1

o si deseamos hacer el rastreo sin sombras, con reflejos, sin transparencia y con sombreados difusos y especulares realizados en ambas caras de las superfícies deberíamos usar las opciones 2 y 8:

polyray xxx.pi -q 10

Nota: La textura no puede ser desactivada.

1.7.2 Conversión de polígonos (Scan conversion).

Para realizar un rastreo más rápido de las imágenes Polyray pueden rastrear la mayoría de los objetos base como una serie de polígonos. Cada polígono es rastreado por conversión utilizando un bufer Z (Z-Buffer) para información de profundidad, y un buffer S (S-Buffer) para información del color.

El proceso de conversión de polígonos no provee soporte por omisión para: sombras, reflexión, o transparencia. Es posible instruir a Polyray para que use el rastreo para desempeñar estas operaciones de sombreado a través del uso de, bien los flags de sombreado globales, bien colocando flags de sombreado para un objeto específico. Un método alternativo para testear rápidamente las sombras utilizando Buffers de sombras está en los ejemplos.

Los requisitos de memoria para ejecutar el rastreo por conversión pueden ser bastante sustanciales. Necesitaremos al menos tanta memoria como la requerida para el rastreo normal, más al menos 7 bytes por pixel para la imagen final. Para seguir correctamente el rastro de profundidad y color 4 bytes son utilizados para la profundidad de cada pixel en el Z-Buffer (32 bits en números de punto flotante), y 3 bytes son utilizado por cada pixel en el S-Buffer (1 byte para rojo, otro para verde, y otro para azul).

Durante la conversión de polígonos, la cantidad de polígonos utilizados para cubrir la superficie de un objeto se controla utilizando las palabras clave "u_steps", y "v_steps". Estos dos valores controlan cuantos pasos alrededor y a lo largo de la superficie de los valores del objeto son generados para crear los polígonos. A mayor número de pasos mejor será la apariencia final. Observe sin embargo que si el objeto es muy pequeño entonces hay una pequeña razón para utilizar un entramado fino - en estos casos se requeriere hacerlo a mano para obtener el mejor balance entre velocidad y apariencia.

Para la generación de superficies isométricas (isosurfaces) para las burbujas (blobs), funciones polinomiales y funciones implícitas, seguido por la poligonalización (polygonalization) de las superficies, es necesario utilizar el algoritmo "marching_cubes". Actualmente el valor de "u_steps" determina la cantidad de divisiones a lo largo del eje x, y el valor de "v_steps" controla la cantidad de divisiones a lo largo del eje y, y a lo largo del eje z. Las versiones futuras pueden introducir un tercer valor para permitir el control independiente de y, y de z.

1.7.3 Modelos inalambricos (Wireframe).

En la mayoría de los casos el modo más rápido de mostrar una imagen es usando su modelo inhalambrico. Polyray provee éste como una variante del proceso de conversión de poligonos. Cuando se dibuja una imagen usando este modelo solo los bordes de los polígonos que son generados como parte del rastreo por conversión son dibujados en la pantalla. Un gran problema con las representaciones inalambricas es que las operaciones de la CSG (Geometría del espacio Constructiva) no se realizan. Si usásemos las intersecciones, diferencias, o recortes de la CSG, podríamos ver una gran cantidad de cosas que no aparecerán en la imagen final.

Observen que hay imágenes que se rastrean más lentamente en la conversión de poligonos y en el modelo inalambrico que con el rastreo normal (raytracing). Estos son típicamente aquellos archivos que contienen una gran cantidad de esferas y conos. El proceso de conversión de poligonos genera cada una de las posibles partes de cada objeto, mientras que el raytracer es capaz de clasificar los objetos y visualizar únicamente las partes visibles de las superficies.

2. Detallada descripción del formato de entrada de Polyray.

Un archivo de entrada describe los componentes básicos de una imagen:

Un punto de vista que caracteriza donde el ojo está, donde está mirando y cual es su orientación.

Los objetos, su forma, colocación, y orientación.

Las fuentes de Luz, su colocación y su color.

Las Texturas para colorear y formar las superficies.

Más allá de los principios basicos, hay muchos componentes que existen ya sean como una conveniencia, como expresiones definibles, o como texturas. Esta sección del documento describe en detalle la sintaxis de todos los componentes de un archivo de entrada.

2.1 Expresiones.

Hay cuatro tipos básicos de expresiones que son utilizados po Polyray:

fexper: Expresión de punto flotante (p.e. 0.5, 2*sin(1.33)). Estos son utilizados en cualquier punto en el que un valor de punto flotante sea necesitado, como el radio de una esfera o la cantidad de contribución de una parte del modelo de iluminación.

vexper: Expresión vectorial (p.e. <0,1,0>, rojo, 12*<2,sin(x),17>+P). Utilizadas para expresiones de color, descripción de posición, descripción de orientaciones, etc.

Matrices: Listas de expresiones (p.e. [0,1,17,42], [< 0,1,0 >, <2*sin(theta),42,- 4>, 2*< 3, 7, 2>].

cexper: Expresiones condicionales (p.e. X < 42).

Las siguientes secciones describen la sintaxis de cada uno de estos tipos de expresiones, así como como la definición de variables en función de las expresiones.

2.1.1 Expresiones Numéricas

En la mayoría de los lugares donde un número puede ser usado (p.e. valores de escala, ángulos, componentes RGB, etc.) una expresión de punto flotante simple (fexper) puede ser usada. Estas expresiones pueden contener cualquera de los siguientes términos:

Val	Un número de punto flotante o valor definido.

'(' fexper ')'	Expresión entre paréntesis.

fexper^fexper	Igual que pow(x,y) -elevar x a y.

fexper*fexper	Multiplicación.

fexper/fexper	División.

fexper+fexper	Adición.

fexper-fexper	Resta.

-fexper	Negación.

acos(fexper)	Arcocoseno, (radianes para todas las funciones trigonométricas).

asin(fexper)	Arcoseno.

atan(fexper)	Arcotangente.

ceil(fexper)	Función de Ceil.

cos(fexper)	Coseno.

cosh(fexper)	Coseno Hiperbólico.

degrees(fexper)	Convierten radianes a grados

exp(fexper)	e^x, función exponencial estándar.

fabs(fexper)	Valor Absoluto.

floor(fexper)	Función Floor.

fmod(fexper, fexper)	Función módulo para punto flotante.

ln(fexper)	Logaritmo Natural.

log(fexper)	Logaritmo de base 10.

noise(vexper, fexper)	Función de ruido correlacionado.

pow(fexper, fexper)	Exponenciación ( x^y ).

radians(fexper)	Convierten grados a radianes.

sawtooth(fexper)	Función Sawtooth funciona (rango 0 -> 1).

sin(fexper)	Seno.

sinh(fexper)	Seno Hiperbólico.

sqrt(fexper)	Raíz Cuadrada.

tan(fexper)	Tangente.

tanh(fexper)	Tangente Hiperbólica.

visible(vexper, vexper)	Retorna 1 si el segundo punto es visible desde el primero.

vexper[i]	Extrae el componente i de un vector o una matriz.

vexper.vexper	Producto escalar de dos vectores

|fexper|	Valor Absoluto (igual que fabs).

|vexper|	Longitud de un vector.

2.1.2 Expresiones Vectoriales.

En la mayoría de los lugares donde un vector puede ser usado (p.e. valor de color, ángulos de rotación, localizaciones, ...), una expresión vectorial está permitida. Las expresiones pueden contener cualquera de los siguientes términos:

vexper + vexper	Adición.

vexper - vexper	Resta.

vexper * vexper	Producto vectorial.

vexper * fexper	Escalado de un vector por un escalar.

fexper * vexper	Escalado de un vector por un escalar.

vexper / fexper	Escalado inverso de un vector por un escalar.

brownian(vexper)	Hace un desplazamiento aleatorio de un vector.

color_wheel(x,y,z)	Rueda de color de RGB utilizando x y z (y ignorada), el color devuelto está basado en <x, z> utilizando el siguiente diagrama:

Los colores intermediarios están generados por interpolación.

rotate(vexper, vexper)	Rota el punto dado en el primer argumento por los ángulos dados en el segundo argumento. (ángulos en grados).

rotate(vexper, vexper,

fexper)	Rota el punto del primer argumento alrededor el eje dado en el segundo argumento, por el ángulo del tercer argumento. (ángulo en grados).

reflect(vexper, vexper)	Refleja el primer vector acerca del segundo vector (particularmente útil en mapas de entornos).

2.1.3 Expresiones Matriciales.

Las matrices son un modo de representar información en una conveniente lista de formas. Un buen uso de las matrices constituye en almacenar un número de ubicaciones para vértices de polígonos o como ubicaciones para objetos en los fotogramas sucesivos de una animación.

Como un ejemplo, un modo de definir un tetraedro (sólido de 4 caras) es definir sus vértices, y cuales de estos vértices construyen sus caras. Utilizando esta información en una declaración de objeto, podemos hacer fácilmente un tetraedro sin usar polígonos.

define caras_del_tetraedro

[< 0, 1, 2>, < 0, 2, 3>, < 0, 3, 1>, < 1, 3, 2>]

define vertices_del_tetraedro

[< 0, 0, sqrt(3)>, < 0, (2*sqrt(2)*sqrt(3))/3, -sqrt(3)/3>,

<-sqrt(2), -(sqrt(2)*sqrt(3))/3, -sqrt(3)/3>,

< sqrt(2), -(sqrt(2)*sqrt(3))/3, .sqrt(3)/3>]

define tcf caras_del_tetraedro

define tcv vertices_del_tetraedro

define tetraedro

object

{

polygon 3,	tcv[tcf[0][0]],

tcv[tcf[0][1]],

tcv[tcf[0][2]]

} +

object

{

polygon 3,	tcv[tcf[1][0]],

tcv[tcf[1][1]],

tcv[tcf[1][2]]

} +

object

{

polygon 3,	tcv[tcf[2][0]],

tcv[tcf[2][1]],

tcv[tcf[2][2]]

} +

object

{

polygon 3,	tcv[tcf[3][0]],

tcv[tcf[3][1]],

tcv[tcf[3][2]]

}

}

Lo que ocurre en la declaración del objeto es que cada polígono recupera una serie de índices de vértices del array "caras_del_tetraedro", entonces lo utiliza dicho índice para recuperar la ubicación real en el espacio de ese vértice.

Otro ejemplo es utilizar una matriz para abastecer una serie de direcciones de vistas de modo que podemos utilizar la animación para generar una serie de fotogramas distintos de la misma escena:

define localizacion <0, 0, 0>

define at_vecs [<1,0,0>, <-1,0,0>, <0,1,0>, <0,-1,0>, <0,0,-1> <0,0,1>]

define up_vecs [<0,1,0>, <0,1,0>, <0,0,1>, <0,0,-1>, <0,1,0>, <0,1,0>]

// Generar seis fotogramas

start_frame 0

end_frame 5

// En cada fotograma se genera la vista que está en una dirección específica.

// Los vectores almacenaros en las matrices "at_vecs", y "up_vecs"

// giran la cámara de tal modo que generan mapas de imagen correctos

// para utilizarlos en mapas de entorno.

viewpoint

{

from location

at location + at_vecs[frame]

up up_vecs[frame]

...

}

... El resto del fichero de datos ...

Ejemplos de archivos: plyhdrn.pi, environ.pi

2.1.4 Expresiones Condicionales.

Las expresiones condicionales son utilizadas en unos de los dos lugares siguientes: El procesamiento condicional de declaraciones (ver sección 2.7) o funciones de valor condicional.

cexper tiene una de los siguientes formas:

!cexper

cexper && cexper

cexper || cexper

fexper < fexper

fexper <= fexper

fexper > fexper

fexper >= fexper

fexper == fexper

vexper == vexper

Un uso de expresiones condicionales es para definir una textura basada en otras expresiones, el formato de esta expresión es:

(cexper ? valor_correcto : valor_falso)

Donde valor_corecto/valor_falso pueden ser valores o bien de punto flotante o bien valores vectoriales. Este tipo de expresión está tomado directamente del equivalente en el LENGUAJE C. Un ejemplo de como se utiliza esto (del archivo "spot1.pi") es:

special surface

{

ambient	(visible(W, throw_offset) == 0

? 0

: (P[0] < 1 ? 1

: (P[0] > throw_lenght ? 0

: (throw_lenght - P[0]) /

throw_lenght

)

)

)

transmission (visible(W, throw_offset) == 1

? (P[0] < 1 ? 0

: (P[0] > thorw_lenght ? 1

: P[0] / throw_lenght

)

)

: 1), 1

}

En este caso los estamentos condicionales son utilizados para determinar las características de la superficie de un cono definiendo la frontera de un reflector. La cantidad de luz ambiente es modificada con la distancia del ápice del cono, la visibilidad del cono se modifica basándose tanto en la distancia como en la determinación de que si el cono esté detrás de un objeto respecto a la fuente de luz.

2.1.5 Expresiones en tiempo de ejecución.

Hay algunas expresiones que solamente tienen significado durante el proceso de rastreo:

I	La dirección del rayo que golpeó el objeto.

P	El punto de intersección en coordenadas del "objeto" (usted puede también utilizar x, y, o z para representar un único componente de P).

N	La normal al punto de intersección en coordenadas "globales".

W	El punto de intersección en coordenadas "globales".

Estas expresiones describen la interacción de un rayo y un objeto. Para utilizarlos efectivamente, necesita entender la distinción entre cordenadas "globales" y coordenadas del "objeto". Las coordenadas del objeto describen un punto o una dirección respecto a un objeto tal como estuvo definido originalmente. Las coordenadas globales describen un punto respecto a un objeto después de haber sido rotado/trasladado/escalado. Típicamente el proceso de texturas se realiza en coordenadas del objeto de modo que cuando el objeto es movido la textura se mueve también. El sombreando por otra parte se realiza en coordenadas globales.

Nota: La capitalización de estas variables es importante.

2.1.6 Etiquetas.

Una conveniencia para crear archivos de entrada es la habilidad para crear etiquteas para sustituir expresiones complejas, como modelos de superfícies, definiciones de objetos, vectores, etc. Se puede realizar de la siguiente forma:

define <nombre_etiqueta> <expresion>

define <nombre_etiqueta> object { ... }

define <nombre_etiqueta> surface { ... }

define <nombre_etiqueta> texture { ... }

define <nombre_etiqueta> transform { ... }

Los objetos, superficies, y las texturas pueden ser asociados como son, utilizando el nombre de la etiqueta, o pueden ser asociados y modificados:

<nombre_etiqueta>,

o

<nombre_etiqueta> { ... modificadores ... },

Polyray sigue el rastro de qué tipo de entidad representa la etiqueta y pasará las expresiones en conformidad a esto.

Nota: No es posible tener dos tipos de entidades referidas por el mismo nombre. Si un nombre es reutilizado, entonces una advertencia serán impresa, y todas las referencias a dicho nombre utilizará la nueva definición.

2.2 Definición del punto de vista.

El punto de vista y sus componentes asociados definen la posición y orientación de la vista que será generada. El formato de la declaración es:

viewpoint

{

from	vexper

at	vexper

up	vexper

angle	fexper

hither	fexper

resolution	fexper, fexper

aspect	fexper

yon	fexper

dither_rays	fexper

dither_objects	fexper

max_trace_depth	fexper

aperture	fexper

focal_distance	fexper

}

El orden de las entradas al definir el punto de vista no es importante, al menos que redefinamos algún campo. (En cuyo caso el último será utilizado.)

Los parámetros son:

aspect	La razón entre la anchura y la altura. (Valor por omisión: 1.0.)

at	Una posición que será el centro de la imagen, en coordenadas globales de XYZ. (Valor por omisión: <0,0,0>)

angle	El campo visual (en grados), del centro de la fila superior al centro de la fila de inferior. (Valor por omisión: 45 grados)

from	La ubicación del ocular en XYZ. (Valor por omisión: <0,0,-10>)

hither	Distancia al frente de la pirámide vista. Cualquier intersección menor que este valor serán ignorado. (Valor por omisión: 1.0 10-3)

resolution	La Cantidad de pixels -ancho x alto- de la imagen. (Valor por omisión: 256 x 256)

up	Vector que define cual eje de coordenadas es el que nos da la dirección de la parte superior de la imagen. (Valor por omisión: <0,1,0>)

yon	Distancia a la parte trasera de la pirámide de vision. Cualquier intersección más allá de esta distancia serán ignorada. (valor por omisión: 1.0 105)

dither_rays	Los rayos que serán ignorados si un número aleatorio dado es superior al valor dado.

dither_objects	Para cada rayo, el chequeo de la superficie se ignorará para un objeto si un número aleatorio es superior al valor dado.

max_trace_depth	Esto le permite ajustar la cantidad de recursividad permitida para escenas con reflejos y/o transparencias. (Valor por omisión: 5)

aperture	Si es mayor que 0, entonces se lanzarán rayos adicionales (controlados por "max_samples" en el archivo de inicialización) para producir una imagen borrosa. (Los mejores valores están entre 0.1 y 0.5.)

focal_distance	Distancia desde el ojo al punto focal donde se encuentren los objetos, es por omision la distancia entre "from" y "at".

Los vectores de visualización serán obligados de tal forma que deben ser perpendiculares al vector formado por los puntos del ojo (from) y el punto de interés (at).

Una declaración típica será:

viewpoint

{

from	<0 , 5, -5>

at	<0, 0, 0>

up	<0, 1, 0>

angle	30

resolution	320, 160

aspect	2

}

En esta declaración el ojo está cinco unidades detrás del origen, cinco unidades sobre el plano x-z y está mirando al origen. La dirección de la parte superior de la imagen está alineada con el eje y, el campo visual tiene 30 grados y el archivo de salida tiene por omisión 320x160 pixels.

En este ejemplo se supone que los pixels son cuadrados, y por lo tanto la razón de aspecto es establecida por ancho/alto. Si estuvieramos generando una imagen para una pantalla en la que la anchura de los pixels son la mitad de su altura entonces la razón de aspecto se establecería a uno.

2.3 Objetos/Superficies

Para hacer imágenes, la luz tiene que golpear en algo. Polyray soporta varias primitivas de objetos, y las siguientes secciones describen la sintaxis para describir dichos objetos, así como la forma en que objetos más complejos pueden ser construidos a partir de los simples.

La declaración de un objeto es la forma en la que polyray asocia una superficie con sus características de iluminación, y orientación. Esta declaración incluye uno de los objetos (esfera, polígono, ...), y opcionalmente: una declaración de textura (puesta a "matte white" -blanco mate- si no se especifica nada), las declaraciones de orientación, o una declaración de caja de límites.

El formato la declaración es:

object

{

<declaración_del_objeto>

[<declaración_de_texturas>]

[<declaración_de_tranformaciones>]

[<declaraciones_de_subdivisiones>]

[declaración_de_caja_de_límites>]

}

Hay tres modos separados por los que un objeto puede ser traducido por Polyray, raytracing (rastreo por rayos), scan convert (conversión de poligonos), o wireframe (modelo inhalambrico). Los pasos tomados por cada uno de estos métodos son:

Raytracing

1)	Encontrar el objeto que parece más cercano al ocular a lo largo del rayo actual. El proceso de límite unificador es el que determina en qué orden los objetos serán probados contra el rayo.

2)	Encontrar todas las intersecciones del rayo con el objeto. (Hasta el número máximo de intersecciones.)

Scan Conversion

1)	El objeto es roto en un número de rectángulos (el número real depende de los valores de "u_steps" y "v_steps" en las declaraciones del objeto).

2)	El rectángulo es capturado de modo que solamente la parte visible es producida.

3)	El polígono capturado es rastreado por conversión de línea en línea. Como la conversión de poligonos tiene lugar, el objeto y las coordenadas globales del polígono son interpolados desde los vértices.

4)	En la medida en que cada pixel es generado por la conversión de poligonos, su distancia del ojo es revisada contra un Búffer Z.

5)	Si la distancia es menor que el valor en el Búffer Z, entonces cualquier CSG y operaciones de captura asociadas con el objeto son realizadas.

6)	Si el pixel pasa los chequeos de CSG y profundidad, entonces el pixel es sombreado utilizando la información de la textura asociada con el objeto. La profundidad al pixel se almacena en el Búffer Z y el color asociado con el pixel se almacena en el Búffer S.

Wireframe

1)	El objeto se trocea en un número de rectángulos (el número real depende de los valores de "u_steps" y "v_steps" en las declaraciones del objeto).

2)	El rectángulo es capturado de modo que solamente la parte visible serán producida.

3)	El rectángulo capturado es exhibido en la pantalla. La CSG no se toma en consideración en una imagen con el modo inhalambrico.

Para determinar si un punto está dentro de un objeto se realiza una función de evaluación que describe al objeto utilizando el punto de intersección. Si el valor es menor o igual a 0 entonces el punto está dentro. Algunos objetos no tienen una zona interior (Superficies triangulares), otros no tienen un interior bien definido (cilindro).

Las siguientes subsecciones describen el formato de las partes individuales de una declaración de objeto. (Nota: La declaración de forma TIENE QUE estar la primera en la declaración, ya que muchas de las operaciones que siguen tienen que tener dicha información para trabajar con el objeto.)

2.3.1 Modificadores de Objetos

2.3.1.1 Modificadores de Posición y Orientación

La posición, orientación, y el tamaño de un objeto puede ser modificado a través de uno de las cuatro transformaciones lineales: traslación, rotación, escalado, y recorte.

2.3.1.1.1 Traslación

La traslación mueve la posición de un objeto por la cantidad de unidades especificadas en el vector asociado. El formato de la declaración es:

translate <xt, yt, zt>

Por ejemplo, la declaración:

translate <0, 20, -4>

mueve el objeto completo 20 unidades a lo largo de del eje y, y 4 unidades hacia atras sobre el eje z.

2.3.1.1.2 Rotación

La rotación gira la posición de un objeto sobre los ejes x, y, y z (en ese orden). La cantidad de rotación se especifica en grados para cada uno de los ejes. La dirección de las rotaciones siguen la convención de la mano izquierda: Si el pulgar de su mano izquierda apunta a lo largo de la dirección positiva de un eje, entonces la dirección de los dedos cerrados es la dirección positiva de rotación.

El formato de la declaración es:

rotate <xr, yr, zr>

Por ejemplo, la declaración:

rotate <30, 0, 20>

rotará el objeto 30 grados sobre el eje x, seguido por 20 grados sobre el eje z.

Recuerde: Las Rotaciones sobre la mano izquierda.

2.3.1.1.3 Escala

La escala altera el tamaño de un objeto por una cantidad dada respecto a cada uno de las ejes de coordenadas. El formato de la declaración es:

scale <xs, ys, zs>

2.3.1.1.4 Recortes

No utilizados frecuentemente, pero ocasionalmente utiles, son los recortes lineales. El recorte, escala el objeto a lo largo de un eje por una cantidad que es proporcional a la ubicación en otro eje. El formato de la declaración es:

shear yx, zx, xy, zy, xz, yz

Típicamente solamente uno o dos de los componentes serán distintos de cero, por ejemplo la declaración:

shear 0, 0, 1, 0, 0, 0

recortará un objeto más y más a la derecha como pueda haciendolo más y más grande. El orden de las letras en la declaración es descriptiva, shear ... ab, ... significa recortar a lo largo de la dirección a por la cantidad "ab" veces la posición b.

Esta declaración deberia probablemente ser dividida en tres: una que asocie el recorte en x con los valores y y z, una que asocie el recorte en y con los valores x y z, y otra que asocie el recorte en z con los valores x e y.

Podría querer mirar el archivo "xander.pi " - éste utiliza recortes en cajas para hacer partes diagonalmente sesgadas de letras.

2.3.1.2 Cajas de límites

Para acelerar el proceso de determinar si un rayo intersecta un objeto y para definir buenos límites para superficies polinomiales y superficies implícitas, se puede especificar una caja de límites. Un breve ejemplo de como se utiliza para definir límites de un polinomio:

define r0 3

define r1 1

define anillo_toroidal

(x^2 + y^2 + z^2 - (r0^2 + r1^2))^2 - 4 * r0^2 * (r1^2 - z^2)

object

{

polynomial anillo_toroidal

shiny_red

bounding_box <-(r0+r1), -(r0+r1), -r1>,

< (r0+r1), (r0+r1), r1>

}

La prueba para intersectar un rayo contra una caja es mucho más rápida que ejecutar la prueba para la ecuación de polinomio. Además la caja ayuda al proceso de conversión de poligonos para determinar donde buscar la superficie del toro.

2.3.1.3 Subdivisión de Objetos

La cantidad de subdivisión de un objeto que se realiza antes de su exhibición como polígonos es ajustable. Estas declaraciones solamente toman efecto durante la conversión de poligonos - es ignorado durante raytracing. Las dos declaraciones son:

u_steps	n

v_steps	m

Donde U se refiere generalmente a la cantidad de pasos "alrededor" del objeto (la cantidad de pasos alrededor del ecuador de una esfera por ejemplo). El parámetro V se refiere a la cantidad de pasos a lo largo del objeto (latitudes de una esfera). Objetos como los conos y cilindros solamente requieren 1 paso a lo largo de V, pero para suavizarlos pueden requerirse muchos pasos en U.

Para las burbujas, polinomios, y superficies implícitas, el componente v_steps juega un doble papel, especificando cuantas subdivisiones son necesarias a lo largo de tanto el eje y como el eje x.

2.3.1.4 Banderas de Sombreando.

Es posible ajustar el sombreado que se realizará para cada objeto. Los valores de cada bit en el flag tienen el mismo significado como el dado para el sombreado global de las sección 1.7.1.4:

1) Shadow_Check	Se generarán sombras.

2) Reflect_Check	Se testearán los reflejos.

4) Transmit_Check	Testeo de la refracción.

8) Two_Sides	Si está activado, se realizará la iluminación en ambas caras de una superficie.

16) Cast_Shadow	Determina si un objeto puede lanzar sombras

32) Primary_Rays	Si está desactivado, entonces los rayos principales (aquellos desde el ojo) no son revisados contra el objeto.

La declaración tiene la forma:

shading_flags xx

Por ejemplo: Si el valor 50 está utilizado para "xx", anteriormente, entonces este objeto puede ser reflexivo y lanzará sombras, sin embargo no se efectuarán pruebas para transparencia y no habrá sombreando de las caras ocultas de las superficies.

Nota: La bandera de sombreado solamente afecta el objeto en que la declaración está hecha. Esto significa que si usted quiere los valores de sombreado afectados por todas las partes si es un objeto CSG, entonces usted necesitará una declaración en cada componente.

2.3.2 Objetos

Los objetos son el nivel más bajo de descripción de forma. Típicamente una escena contendrá muchos objetos, apareciendo ya sea individualmente o como conjuntos, utilizando las operaciones de la CSG u objetos enrejados (Gridded Objects).

Las formas de los objetos que pueden ser usados en Polyray son las siguientes:

Superficies de Bezier

Burbujas

Cajas

Conos

Cilindros

Discos

Superficies Implícitas

Campos de Elevación

Superficie de Lathe

Parábolas

Polígonos

Superficies Polinomiales

Esferas

Superficies de barrido

Anillos Toroidales

Superficies Triangulares

Las descripciones de cada una de estas formas primarias, así como referencias a ficheros de datos que las muestran serán analizadas en las siguientes subsecciones. Siguiendo la descripción de los objetos podremos ver como construir las descripciones de la CSG y de las rejillas.

2.3.2.1 Superficies de Bezier

Una superficie de Bezier es una superficie bicubica que interpola sus vértices de control. La superficiea está definida en función de una matriz de 4 filas y 4 columnas de vértices de control, así como varios valores de ajuste.

El formato de la declaración es:

bezier

<tipo_de_subdivision>,

<valor_de_alisamiento>,

<subduvisiones_u>,

<subdivisiones_v>,

[array de 16 vértices (puntos),

p. e. <x0,y0,z0>, <x1,y1,z1>, ..., <x15,y15,z15>]

El tipo de subdivisión controla como la superficie está representada internamente. Los valores válidos y su significado son:

1)	Almacenar solamente la información mínima necesitada. Requiere menor capacidad de almacenamiento pero utiliza más tiempo durante el rastreo.

2)	Almacena un árbol jerárquico de esferas limitadoras que contienen superficies más pequeñas y más pequeñas de la superficie. Este árbol es utilizado durante el rastreo para acelerar el proceso de intersección rayo-superfície. Más rápida pero requiere más memoria.

El valor de alisamiento es utilizado para determinar el número de veces que una superficie debería ser subdividida antes de que pueda ser considerada como tal "superficie". Contra más pequeño sea este valor más veces se subdivirá la superficie (limitada por los dos siguientes valores).

La cantidad de niveles de subdivisión de la superficie, en cada dirección, está controlada por los dos parámetros "subdivisiones_u", y "subdivisiones_v". Cuanto mayor número de subdivisiones exista se obtendra una mejor aproximación de la superficie, sin embargo se requerirá mayor capacidad de almacenamiento y más tiepo de proceso.

Un ejemplo de superficie de Bezier es:

object

{

bezier 2, 0.05, 3, 3,

<0,0,2>, <1,0,0>, <2,0,0>, <3,0,-2>,

<0,1,0>, <1,1,0>, <2,1,0>, <3,1,0>,

<0,2,0>, <1,2,0<, <2,2,0>, <3,2,0>,

<0,3,2>, <1,3,0>, <2,3,0>, <3,3,-2>

rotate <30, -70, 0>

shiny_red

}

Ejemplos: bezier0.pi, teapot.pi, teapot.inc

2.3.2.2 Burbujas

Una burbuja describe un campo potencial suave alrededor uno o más componentes esféricos, cilíndricos o planos.

El formato de la declaración es:

blob umbral_de_burbuja:

<componentes_de_la_burbuja_1>

[,<componentes_de_la_burbuja_2>]

[,<componentes_de_la_burbuja_3>]

[, etc... por cada componente]

El umbral de burbuja es el valor potencial mínimo que será considerado cuando se examine la interacción de los diversos componentes de la burbuja. Cada componente de la burbuja puede ser uno de los siguientes:

sphere	<x, y, z>, fortaleza, radio

cylinder	<x0, y0, z0>, <x1, y1, z1>, fortaleza, radio

plane	<nx, ny, nz>, d, fortaleza, distancia

El componente de fortaleza describe lo fuerte que el campo potencial es alrededor del centro del componente, el radio describe la distancia máxima en la que el componente interactuará con los otros componentes. Para una componente esférico de burbuja el vector <x,y,z> da el centro del campo potencial alrededor del componente. Para un componente de burbuja cilíndrico el vector <x0, y0, z0> define un fin del eje de un cilindro, el vector <x1, y1, z1> define la otra terminal del eje de un cilindro. Un componente de burbuja plano está definido por la ecuación normal del plano <nx, ny, nz> definiendo el vector normal al plano y "d" define la distancia del plano desde el origen a lo largo del vector normal. Nota: Los extremos de un componente de burbuja cilíndrico están cubiertos por semiesferas. Los dos puntos y las comas en la declaración realmente son importantes.

Un ejemplo de una burbuja es:

object

{

blob 0.5:

cylinder <0, 0, 0>, <5, 0, 0>, 1, 0.7,

cylinder <1, -3, 0>, <3, 2, 0>, 1, 1.4,

sphere <3, -0.8, 0>, 1, 1,

sphere <4, 0.5, 0>, 1, 1,

sphere <1, 1, 0>, 1, 1,

sphere <1, 1.5, 0>, 1, 1,

sphere <1, 2.7, 0>, 1, 1

texture

{

surface

{

color red

ambient 0.2

diffuse 0.8

specular white, 1

microfacet Phong 5

}

}

}

Nota: una burbuja es esencialmente una colección de polinomios de cuarto orden, es posible especificar qué raíz de cuarto grado se resoverá para ser utilizada. Vea la sección 2.3.2.12, "Superficies Polinomiales" para una descripción de la declaración del "root_solver" -calcualdor de raíces.

Archivos: blob.pi

2.3.2.3 Cajas

Una caja es sólido rectangular que tiene sus bordes alineados con los ejes x, y, y z. Está definido en función de dos esquinas diagonalmente opuestas. La alineación puede ser cambiada mediante rotaciones después de la declaración del objeto.

El formato de la declaración es:

box <x0, y0, z0>, <x1, y1, z1>

Generalmente la convención es que el primer punto sea el punto frontal de la parte izquierda inferior y el segundo es el punto posterior de la parte superior derecha. La siguiente declaración tiene cuatro cajas apiladas unas encima de las otras:

define piramide

object

{

object { box <- 1, 3,- 1>, < 1, 4, 1> } +

object { box <- 2, 2,- 2>, < 2, 3, 2> } +

object { box <- 3, 1,- 3>, < 3, 2, 3> } +

object { box <- 4, 0, -4>, < 4, 1, 4> }

matte_blue

}

Ficheros: boxes.pi

2.3.2.4 Conos

Un cono está definido en función de un punto de base, un punto de ápice, y los radios a aquellos dos puntos. Observen que los conos no son cerrados.

El formato de la declaración es:

cone <x0, y0, z0>, r0, <x1, y1, z1>, r1

Una declaración de ejemplo de un cono es:

object

{

cone <0, 0, 0>, 4, <4, 0, 0>, 0

shiny_red

}

Archivos: cone.pi, cones.pi

2.3.2.5 Cilindros

Un cilindro está definido en función de un punto inferior, un punto superior, y su radio. Observese que los cilindros no estan cerrados.

El formato de la declaración es:

cylinder <x0, y0, z0>, <x1, y1, z1>, r

Un ejemplo de un cilindro es:

object

{

cylinder <-3, -2, 0>, <0, 1, 3>, 0.5

shiny_red

}

Archivos: cylinder.pi

2.3.2.6 Discos

Un disco está definido en función de un centro, un vector normal y ya sea un radio, o utilizando un radio interior y un radio exterior. Si solamente se diera un radio, entonces el disco tiene la apariencia de una moneda extraplana. Si dos radios son dados, entonces el disco coge la forma de un anillo donde el disco se extiende desde el primer radio al segundo radio. Los usos típicos para discos son como cubiertas para los conos y cilindros, o como suelos planos (utilizando un gran radio).

El formato de la declaración es:

disc <cx, cy, cz>, <nx, ny, nz>, r

o

disc <cx, cy, cz>, <nx, ny, nz>, ir, or

El vector central <cx, cy, cz> define donde se localiza el centro del disco, el vector normal <nx, ny, nz> define la dirección que es perpendicular al disco. p.e. Un disco teniendo el centro < 0,0,0 > y vector normal < 0,1,0 > pondría el disco en el plano x-z con el eje y saliendo directamente hacia afuera del centro.

Un ejemplo de un disco es:

object

{

disc <0, 2, 0>, <0, 1, 0>, 3

rotate <-30, 20, 0>

shiny_red

}

Nota: Un disco es infinitamente delgado. Si usted mirara al canto este desapareceria.

Archivos: disc.pi

2.3.2.7 Superficies Implícitas.

El formato de la declaración es:

function f(x, y, z)

La función f(x, y, z) puede ser cualquier expresión algebráica compuesta de las variables: x, y, z, un valor numérico (p.e. 0.5), los operadores: +, -, *, /, ^, y las funciones: cos, cosh, exp, fabs, ln, log, sin, sinh, tan, tanh. El código ni es particularmente rápido, ni totalmente exacto, sin embargo la capacidad para rastrear por rayos en tan basta clase de funciones, mediante un programa SW es (Creo), único en Polyray.

La soluciones que serán encontradas por el camino del rayo están determinadas por lo siguiente:

Si hay una caja de límites, entonces los puntos de entrada y salida del rayo con la caja serán utilizados como el intervalo de búsqueda.

Si no hay caja de límites entonces el intervalo desde 0.01 a 100 será utilizado.

Las Soluciones deben de estar distanciadas unas de otras por un valor mínimo de 1.0 10-4.

Nota: El valor absoluto puede estar escrito con barras verticales, p.e. |x|^0.75.

Los siguientes objetos están tomados de "sombrero.pi" y es una superficie que se parece mucho a las ondulaciones de la superficie del agua.

define a_const 1.0

define b_const 2.0

define c_const 3.0

define two_pi_a 2.0 * 3.14159265358 * a_const

// Define una superfície senoidal decreciente (sombrero mexicano)

object

{

function y - c_const * cos(two_pi_a * sqrt(x^2 + z^2)) *

exp(-b_const * sqrt(x^2 + z^2))

matte_red

bounds object

{

box <-4, -4, -4>, <4, 4, 4>

}

}

Archivos: sinsurf.pi, sectorl.pi, sombrero.pi, superq.pi, zonal.pi

2.3.2.8 Campos de Elevación (Height Fileds)

Hay dos modos en los que se pueden especificar los campos de elevación, ya sea utilizando información almacenada en un archivo de formato Targa, o utilizando una función implícita de la forma y=f(x,z).

La orientación por defecto de un campo de elevación es que el campo completo yace en el cuadrado 0 <= x <= 1, 0 <= z <= 1. Los campos de elevación basados en ficheros están siempre en dicha orientación, los campos de elevación implícitos pueden opcionalmente ser definidos sobre un área diferente al plano x-z. La elevación es utilizada para y.

2.3.2.8.1 Campos de Elevación basados en ficheros

La información de los campos de elevación puede ser leida desde un fichero de formato de Targa. Los únicos formatos actualmente sostenidos tienen 8, 16 y 24 bits descomprimidos.

Utilice "smooth_" en a la declaración, para realizar un paso extra que calculará vectores normales al campo de elevación para cada punto dentro del campo. El resultado de esto es una apariencia de gran suavidad, a expensas de gastar alrededor de tres veces más cantidad de memoria.

El formato de la declaración es:

height_field "nombre de fichero"

smooth_height_field "nombre de fichero"

El programa de muestra "wake.c" genera un archivo Targa que simula el rastro detrás de un barco.

Archivos de muestra: wake.pi (requiere que "wave.tga" sea generado por "wake.c")

El modo en que los valores de pixel del archivo son interpretados se examina en las siguientes secciones.

2.3.2.8.1.1 Formato de 8 bit

Cada pixel en el archivo (Targa de tipo 3, imagenes de escala de grises) está representado por un byte único. El byte está tratado como un entero con signo, dando a un rango de valores desde -127 a 127.

Si usted estuviera generando un archivo Targa para utilizar en Polyray, dada una altura, añadir 128 a la altura y escribirlo como un carácter sin signo (unsigned char). El siguiente fragmento de código muestra cómo podría ser las declaraciones.

float altura;

FILE *f_out;

... calcular cada punto ...

fputc(unsigned char) (altura += 128.0), f_out);

2.3.2.8.1.2 Formato de 16 bits

Cada pixel en el archivo (Targa de Tipo 1 o tipo 2) está representado por dos bytes, primero el bajo despues el alto. El byte alto define la parte entera de la altura, el byte inferior describe la parte fraccional escalada por 255. El valor completo es desplazar por 128 para compensar la naturaleza sin signo de los bytes de almacenamiento. Como un ejemplo los valores alto=140, bajo=37 serían traducidos a la altura:

(140 + 37 / 256) - 128 = 12.144

I gualmente si usted estuviera generando un archivo Targa para utilizarlo en Polyray, dada una altura, añadir 128 a la altura, extraer la parte entera, entonces extraer la parte fraccional multiplicada por 256. El siguiente fragmento de código muestra un modo de generar los bytes bajos y altos de un número de punto flotante.

unsigned char bajo, alto;

float altura;

FILE *f_out;

...

altura += 128.0;

alto = (unsigned char) altura;

altura -= (flota) alto;

bajo = (unsigned char) (256.0 * altura);

fputc(bajo, f_out);

fputc(alto, f_out);

2.3.2.8.1.3 Formato de 24 bits

El componente rojo define la parte entera de la altura, el componente verde almacena la parte fraccional esclada por 255, el componente azul es ignorada. El valor completo es desplazar por 128 para compensar la naturaleza sin signo del valor RGB. Como un ejemplo los valores r=140, g=37, y b=0 serían traducidos a la altura:

(140 + 37 / 256) - 128 = 12.144

Igualmente si usted estuviera generando un archivo Targa para utilizarlo con Polyray, dada una altura, añadir 128 a la altura, extraer la parte entera, entonces extraer la parte fraccional escalada. El siguiente fragmento de código muestra un modo de generar los componentes de RGB de un número de punto flotante.

unsigned char	r, g, b;

float	altura;

FILE	*f_out;

...

altura += 128.0;

r = (unsigned char) altura;

altura -= (flotat) r;

g = (unsigned char) (256.0 * altura);

b = 0;

fputc(b, f_out);

fputc(g, f_out);

fputc(r, f_out);

2.3.2.8.2 Campos de Elevación Implícitos

Otro modo de definir los campos de elevación es evaluando una función matemática sobre una cuadricula. Dada una función y=f(x, z), Polyray evaluará la función sobre un área especifica y generará un campo de elevación basado en la función. Este método puede ser utilizado para generar imágenes de tipos de funciones que no son fácilmente representadas por colecciones de objetos más simples.

Los formatos válidos de la declaración son:

height_fn	xsize, zsize, min_x, max_x, min_z, max_z, <expresión>

height_fn	xsize, zsize, <expresión>

smooth_height_fn	xsize, zsize, min_x, max_x, min_z, max_z, <expresión>

smooth_height_fn	xsize, zsize, <expresión>

Si los cuatro valores min_x, max_x, min_z, y max_z no están definidos entonces el cuadrado por omisión será 0 <= x <= 1, 0 <= z <= 1.

Por ejemplo,

// Definen constantes para la función de sombrero mexicano

define a_const 1.0

define b_const 2.0

define c_const 3.0

define two_pi_a 2.0 * 3.14159265358 * a_const

// Define una superfície senoidal decreciente

object

{

height_fn	80, 80, -4, 4, -4, 4,

c_const * cos(two_pi_a * sqrt(x^2 + z^2)) *

exp(-b_const * sqrt(x^2 + z^2))

shiny_red

}

construirá un campo de elevación de 80x80, cubriendo el área de -4 <= x <= 4, y -4 <= z <= 4.

Compare el tiempo de ejecución y la calidad visual de la función sombrero tal como se define en "sombfn.pi" con la función sombrero tal como se define en "sombrero.pi". La anterior utiliza una representación de campo de elevación y lo hace bastante rápidamente. Este último utiliza una representación de una función general y da más suavidad a la imagen pero es mucho más lenta.

Archivos: sombfn.pi, sinfn.pi

2.3.2.9 Superficies de Lathe

Una superficie de Lathe es un polígono que ha sido revolucionado alrededor del eje y. Esta superficie le permite construir objetos que son simétricos alrededor de un eje, simplemente definiendo puntos en dos dimensiones.

El formato de la declaración es:

lathe

<tipo>,

<dirección>,

<número_total_de_vertices>,

<vert1.x, vert1.y, vert1.z>

[, <vert2.x, vert2.y, vert2.z>]

[, etc. hasta_ número_total_de_vertices vértices]

El valor de <tipo> es o uno 1, o 2. Si vale 1, entonces la superficie girará simplemente los segmentos de línea. Si el valor tiene 2, entonces la superficie serán representada por una spline que se aproxima a los segmentos de línea en donde fueron dados. Una superficie de Lathe de tipo 2 es una manera de suavizar las esquinas en un conjunto de segmentos de línea.

El valor del vector <dirección> es utilizado para cambiar la orientación de la superfície de Lathe. Para una superficie de Lathe que va directamente hacia arriba y hacia abajo del eje y, usar <0, 1, 0> para la "dirección". Para una superficie de Lathe que yace en el eje x, utilizaríamos <1, 0, 0> para la dirección.

Archivos: lathe1.pi, lathe2.pi

Observe que la CSG trabajará correctamente si usted cierra la superfície de Lathe -esto es, hacer que el punto final del Lathe sea el mismo que el punto de comienzo, o hacer que el valor x de los puntos de comienzo y fin sean cero. Lathes, a diferencia de los polígonos no son automáticamente cerrados por Polyray.

Nota: Como una superficie de Lathe (tipo 2) es un polinomio de cuarto grado, es posible especificar cual de las raíces queremos utilizar. Ver la sección 2.3.2.12, "Superficies Polinomiales" para una descripción de la declaración del "solucionador de raíces".

2.3.2.10 Parábolas

Una parábola está definida en función de un punto inferior, un punto superior, y el radio de la parte superior.

El formato de la declaración es:

parabola <x0, y0, z0>, <x1, y1, z1>, r

El vector <x0, y0, z0> define la parte superior de la parábola -la parte que llega a un punto. El vector <x1, y1, z1> define la parte inferior de la parábola, el ancho de la parábola en este punto debe ser "r".

Un ejemplo de una declaración de parábola es:

object

{

parabola	<0, 6, 0>, <0, 0, 0>, 3

translate	<16, 0, 16>

steel_blue

}

Se parece en cierta medida a un salero de mesa con la parte superior redondeada y la base en el plano x-z.

2.3.2.11 Polígonos

Aunque los polígonos no son muy interesantes matemáticamente, hay muchas clases de objetos que son más fáciles de representar con polígonos. Polyray supone que todos los polígonos son cerrados y automáticamente añade un lado desde el último vértice al primero.

El formato de la declaración es:

polygon	<número_total_de_vértices,

<vert1.x, vert1.y, vert1.z>

[,<vert2.x, vert2.y, vert2.z>]

[, etc. hasa <número_total_de_vértices> vértices]

Al igual que con la esfera, observe la coma que separa cada vértice del polígono.

Utilizo polígonos como suelo en una gran cantidad de imágenes. Son un poco más lentos que el plano correspondiente, pero para el rastreo por conversión son muchos más fáciles de manipular. Un ejemplo de un tablero de ajedrez realizado con polígono sería:

object

{

polygon	4,

<-20, 0,- 20>, <- 20, 0, 20>,

< 20, 0, 20>, < 20, 0,- 20>

texture

{

checker matte_white, matte_black

translate <0, -0.1, 0>

scale <2, 1, 2>

}

}

2.3.2.12 Superficies Polinomiales

El formato de la declaración es:

polinomial f(x, y, z)

La función f(x, y, z) tiene que ser un polinomio simple, p.e. x2+y2-1.0 es la definición de una esfera de radio 1 centrada en (0,0,0). Ver sección 4.1 para más detalles de las restricciones en la forma del polinomio.

Para ecuaciones de cuarto grado, hay tres modos disponibles para resolver las raíces, especificando cuál es deseado, es posible ajustar o bien la calidad o bien la velocidad. El método de Ferrari es el más rápido, pero también el más inestable numéricamente. Por defecto el método de Vieta es utilizado. Las secuencias de Sturm (que son la más lentas) deberían ser usadas donde se desee la más alta calidad.

La declaración de cual de los tres métodos se desea para resolver las raíces es una de las siguientes:

root_solver Ferrari

root_solver Vieta

root_solver Sturm

(La capitalización es importante -estos son sustantivos adecuados después de todo.)

Nota: Las inexactitudes numéricas inevitables hacen que no todas las superficies polinomiales funcionen correctamente en todas las direcciones.

El siguiente ejemplo, tomado de "devil.pi" define un polinomio de cuarto grado. El objetivo de capturar el objeto mediante la CSG en arreglar las partes de la superficie que no nos interesan. La declaración de caja de límites ayuda a las rutinas del rastreo por conversion para buscar la superficie.

// Variante de una curva del diablo en el espacio tridimensional. Esta

// figura tiene una parte de superior y una parte inferior que son muy

// similares a un hyperboloide de una hoja, sin embargo la región

// central está pellizcadada en el medio dejando dos agujeros.

object

{

object

{

polynomial x^4 + 2 * x^2 * z^2 - 0.36 * x^2 - y^4 +

0.25 * y^2 + z^2

root_solver Ferrari

}

&

object

{

box { <-2, -2, -0.5>, < 2, 2, 0.5> }

}

bounding_box <-2, -2, -0.5>, <2, 2, 0.5>

rotate <10, 20, 0>

translate <0, 3, -10>

shiny_red

}

Nota: a medida que el orden del polinomio asciende, la precisión numérica requerida para hacer la superficie correctamente también asciende. A partir de las ecuaciones de tercer y cuarto grado comienza a aflorar el problema del conseguir determinar todas las sombras correctamente. El resultado son manchas negras en la superficie. Usted puede resolver este problema hasta cierto punto haciendo el valor de "shadow_tolerance" mayor. Para ecuaciones de cuarto o superior grado, debería utilizar un valor de al menos 0.05, en vez del valor por omisión 0.001.

Archivos: torus.pi, y muchos otros

2.3.2.13 Esferas.

Las esferas son los objetos tridimensionales más fáciles de rastrear (render). Con las esferas disfrutará una ventaja de velocidad sobre la mayoría de los otros objetos base.

El formato de la declaración es:

sphere <centro.x, centro.y, centro.z>, radius

Anote la coma después del vector central, realmente es necesario.

Mi archivo de medición básico es una esfera única, iluminada por una luz única. La definición de la esfera es:

object

{

sphere <0, 0, 0>, 2

shiny_red

}

Archivos: sphere.pi

2.3.2.14 Superficies de barrido

Una superficie de barrido, también referida como una superficie extruída, es un polígono que ha sido barrido a lo largo de una dirección dada. Puede ser utilizado para hacer travesaños multi-cara (multi-sided beams), o para crear objetos parecidos a cintas.

El formato de la declaración es:

sweep <tipo>, <dirección>, <número_total_de_vértices>,

<vert1.x, vert1.y, vert1.z>

[,<vert2.x, vert2.y, vert2.z>]

[, etc. hasta <número_total_de_vértices vértices>]

El valor de <tipo> es 1, o 2. Si el valor tiene 1, entonces la superficie serán un conjunto de cuadrados conectados. Si el valor tiene 2, entonces la superficie serán representada por una spline que se aproxima a los segmentos de línea que fueron dados en la definición.

El valor del vector <dirección> se utiliza para cambiar la orientación de la superfície de barrido. Para una superficie de barrido que es extruída directamente hacia arriba y hacia abajo sobre le eje y, usar <0, 1, 0> para la <dirección>.

El tamaño del vector <dirección> también afectará la cantidad de extrusión, p.e. Si |dirección|=2, entonces la extrusión será dos unidades en esa dirección.

Un ejemplo de una superficie de barrido sería:

// Superfície hecha de splines cuadráticas conectadas.

object

{

sweep	2, <0, 2, 0>, 16,

<0, 0>, <0, 1>, <-1, 1>, <-1, -1>,

<2, -1>, <2, 3>, <-4, 3>, <-4, -4>,

<4, -4>, <4, -11>, <-2, -11>, <-2, -7>,

<2, -7>, <2, -9>, < 0, -9>, < 0, -8>

translate	<0, 0, -4>

scale	<1, 0.5, 1>

rotate	<0, -45, 1>

translate	<10, 0, -18>

shiny_yellow

}

Archivos: sweep1.pi, sweep2.pi

Observe que la CSG trabajará correctamente si cerramos la superfície - eso es hacer el punto final igual al punto incial. A diferencia de los polígonos no son automáticamente cerrados por Polyray.

2.3.2.15 Anillos Toroidales

Los anillos toroidales sos superficies con la forma de un buñuelo que está definido por un punto central, la distancia del punto central al medio del anillo del buñuelo, el radio del anillo del buñuelo, y la orientación de la superfície.

El formato de la declaración es:

torus r0, r1, <centro.x, centro.y, centro.z>, <dir.x, dir.y, dir.z>

Como un ejemplo, un anillo toroidal que tiene como radio mayor 1, como radio menor 0.4, y está orientado de modo que el anillo yace en el plano x-z estaría declarado como:

object

{

torus 1, 0.4, <0, 0, 0>, <0, 1, 0>

shiny_red

}

Nota: como un anillo toroidal es un polinomio de cuarto orden, es posible especificar cuales de los tres solucionadores de raices usar. Ver la sección 2.3.2.12, "Superficies Polinomiales" para una descripción la declaración del "root_solver".

Archivos: torus.pi

2.3.2.16 Superficies Triangulares

Una superficie triangular está definida por un conjunto de vértices y sus vectores normales. Cuando se calcula la información de sombreado para una superficie triangular, la información de los vectores normales es utilizada para interpolar el vector final normal del punto de intersección para producir un triángulo de sombreado suave.

El formato de la declaración es:

patch <vert1.x, vert1.y, vert1.z>, <norm1.x, norm1.y, norm1.z>,

<vert2.x, vert2.y, vert2.z>, <norm2.x, norm2.y, norm2.z>,

<vert3.x, vert3.y, vert3.z>, <norm3.x, norm3.y, norm3.z>

La información de mancha suave es generada generalmente como la salida de otro programa.

2.3.3 Geometría Del Espacio Constructiva (CSG)

Los objetos pueden ser definidos en función de la unión, intersección, e inversión de otros objetos. Las operaciones y los símbolos utilizados son:

csgexper + csgexper	- Unión

csgexper * csgexper	- Intersección

csgexper - csgexper	- Diferencia

csgexper & csgexper	- Cortar el primer objeto por el segundo

~csgexper	- Invertir

(csgexpe)	- Expresión entre Paréntesis

La unión recopila simplemente dos objetos juntos. La unión es un modo conveniente de agrupar objetos para poder transformarlos como un grupo. La intersección mantiene solamente aquellas partes de cada objeto que estan "dentro de" el otro objeto. La diferencia mantiene todas las partes de los dos objetos que estan dentro del primer objeto y fuera del segundo. El recorte retira todas las partes del primer objeto que estan fuera del segundo. La operación de inversión, invierte el "dentro de" para pasar a ser el "afuera" y viceversa. (p.e. a - b es lo mismo que a * ~b).

Observe que la intersección y la diferencia requieren que el interior y el exterior esten vacios. No todos los objetos primarios tienen los lados bien definidos. Estos son: Esferas, Cajas, Polinomios, Burbujas, y Funciones.

Otras superficies que no siempre tienen unas interior/esterior "vacio", pero que trabajan razonablemente bien en las intersecciones de CSG son: los Cilindros, Conos, Discos, Superfícies de Lathe, Parábolas, Polígonos, y Superfícies de barrido.

Los Cilindros, Conos, y Parábolas trabajan correctamente, pero los extremos abiertos de estas superficies también serán abriertos en el consiguiente CSG. Para cerrarlos puede utilizar un disco.

Usar Discos, y Polígonos en un CSG es realmente lo mismo que hacer un CSG con el plano en el que radican. De hecho, un disco grande es una excelente opción para recortar o intersectar un objeto, ya que la prueba de interno/externo es muy rápida.

Las superfícies de Lathe, y de barrido usan la regla de Jordán para determinar si un punto esta dentro. Esto significa que dado un punto a chequear, si una línea desde ese punto al infinito cruza la superficie un número primo de veces, entonces el punto está dentro. El resultado neto es que si la superfície de Lathe o la de barrido no está cerrada, entonces se pueden obtener resultados raros en una intersección de la CSG (o diferencia).

Los campos de elevación no trabajan bien con la CSG.

Como un ejemplo, el siguiente archivo generará una vista de una esfera de radio 1 con un agujero de radio 0.5 en el centro:

viewpoint

{

from <0,0,-8>

at <0,0,0>

up <0,1,0>

angle 30

resolution 160, 160

}

background white

light <0, 20, -40>

include "colors.in2c"

define cylinder_z object

{

cylinder <0,0,-2>, <0,0,2>, 0.5

}

define unit_sphere object

{

sphere <0,0,0>, 1

}

// Define un objeto CSG eliminado el cilindro de la esfera

object

{

unit_sphere {shiny_red} - cylinder_z {shiny_yellow}

rotate <0,20,0>

}

Archivos: lens.pi, polytope.pi

2.3.4 Objetos enrejados (Gridded Objects)

Un objeto enrejado es un modo de representar sólidamente un array rectangular de objetos utilizando un mapa de imagen. Cada objeto está situado dentro de un cubo 1x1 que tiene su esquina inferior izquierda en la ubicación <i,0,j> y su esquina superior derecha en <i+1,1,j+1>. El índice de color de cada pixel en el mapa de imagen es utilizado para determinar cual de un conjunto de objetos será situado en la posición correspondiente del espacio.

El objeto enrejado es mucho más rápido de hacer que la disposición correspondiente de objetos. El mayor inconveniente es que cada objeto tiene que estar escalado y trasladado para acomodar completamente el cubo 1x1x1 que tiene esquinas en <0,0,0> y <1,1,1>.

El tamaño del cuadriculado completo está determinado por la cantidad de pixels de la imagen. Una imagen de 16x32 iría desde 0 a 16 a lo largo del eje x y la última fila variaría desde 0 a 16, a 31 unidades en z fuera del eje x.

El formato de la declaración es:

gridded "imagen.tga",

object1

object2

object3

...

Un ejemplo de como un objeto enrrejado se declara sería:

define tiny_sphere

object

{

sphere <0.5, 0.4, 0.5>, 0.4

}

define pointy_cone

object

{

cone <0.5, 0.5, 0.5>, 0.4, <0.5, 1, 0.5>, 0

}

object

{

gridded "grdimg0.tga",

tiny_sphere { shiny_coral }

tiny_sphere { shiny_red }

pointy_cone { shiny_green }

traslate <-10, 0, -10>

rotate <0, 210, 0>

}

En la imagen "grdimg0.tga", hay un total de 3 colores utilizados, cada pixel que utiliza el índice de color 0 generará una esfera de color coral brillante, cada pixel que utilice el índice 1 generará una esfera roja brillante, cada pixel que utilice el índice 2 generará un cono verde brillante, y cualquier otro índice de color utilizado en la imagen dejará el espacio correspondiente vacío.

Archivos: grid.pi, river.pi

2.3.5 Marcando límites

El marcar límites es utilizado por Polyray para clasificar los objetos en la escena a lo largo de las ejes de coordenadas. Para escenas con muchos objetos, el resultado es reducir enormemente el tiempo de ratreo, en oposición a imágenes no optimizadas.

Esta operación clasificadora puede guiar a la generación de muchos nuevos objetos que contendrán a los definidos en el fichero de datos.

Marcar límites trabaja mejor cuando hay muchos objetos pequeños, y cuando los objetos están orientados de modo tal que pueden ser separados por los límites.

2.4 Color e iluminación

El espacio de color que utiliza Polyray es el RGB, con los valores de cada componente especificados como unos valores desde 0 a 1. El modo en el que el color y sombreado de superficies se especifica se describe en las siguientes secciones.

Los colores RGB están definidos como uno vector de tres componentes, como <0.6, 0.196078, 0.8>, o como uno de los colores del X11R3 (p.e. para el valor dado es Darkorchid). Un día de estos cuando tenga ganas de mecanografiar y no de pensar (o si los encontrara en línea), los pondré en los colores del X11R4.

El coloreado de objetos está determinado por la interacción de luces, la forma de la superficie impactante, y las características de la superficie misma.

2.4.1 Fuentes de Luz

Las fuentes de luz pueden ser: fuentes de luz de posición simples, luces zonales, o luces con texturas. Ninguna de estas luces tiene un tamaño físico. Las luces no aparecen en la escena, solamente los efectos de las luces.

2.4.1.1 Luces Posicionales

Una luz de posición está definida por su color de RGB y sus localización en el espacio.

El formato de la declaración es:

light <color>, <ubicación>

light <ubicación>

La segunda declaración utilizará blanco como color.

2.4.1.2 Luces Zonales (Spot Lights)

El formato de la declaración es:

spot_light	<color>, <ubicación>, <pointed_at>,

<Tightness>, <Angle>, <Falloff>

spot_light	<ubicación>, <pointed_at>

La <ubicación> del vector define la posición de la luz, el vector <pointed_at> define el punto al que la luz se dirige. Los componentes opcionales son:

<color>	El color del reflector.

<Tightness>	La función de potencia utilizada para determinar la forma del "Spot light".

<Angle>	El ángulo (en grados) del efecto completo de la luz.

<Falloff>	Un ángulo mayor en el que la cantidad de luz cae a nada.

Una declaración de muestra es:

spot_light white, <10,10,0>, <3,0,0>, 3, 5, 20

Archivos: spot0.pi, spot1.pi

2.4.1.3 Luces con texturas

La luces con texturas son una extensión de las luces puntuales que utilizan una función (incluyendo a los mapas de imágen) para describir la intensidad y color de la luz en cada dirección. El formato de la declaración es:

textured_light

{

color fexper

[escale/translate/rotate/shear]

}

Archivos: environ.pi, ilight.pi

2.4.2 Color de Fondo

El color de fondo es el utilizado si el rayo actual no golpea ningún objeto. El color puede ser cualquier expresión vectorial, aunque generalmente es un valor RGB simple.

El formato de la declaración es:

background <R, G, B>

o

background <color>

Si no utilizase color de fondo se establecería éste a negro.

Un truco interesante que puede ser realizado con el fondo, es utilizar un mapa de imagen como el color de fondo (es también un modo de traducir de un formato Targa a otro). El modo en que esto puede realizar es:

background planar_imagemap(image"test1.tga", P))

Observen que hay problemas asociados con los fondos que usan texturas -si tuviera reflectividad en la escena y un rayo reflejado no golpeara un objeto, éste puede reflejar una parte no deseada del fondo.

2.4.3 Texturas

Polyray soporta algunos procedimientos de texturas simples: Un modelo de sombreado estándar, un verificador de texturas, una textura hexagonal, una textura de ruido, y texturas en capas. Además, soporta una textura muy flexible (aunque más lenta) la textura funcional. La sintaxis general de una textura es:

texture { [declaración de textura] }

o

texture_sym

Donde "texture_sym" es una declaración de textura previamente definida.

2.4.3.1 Procedimientos de Texturas

2.4.3.1.1 Modelo de Sombreado Estándar

A diferencia de muchos otros trazadores de rayos, la ssuperficies en Polyray no tienen un color único que es utilizado por todos los componentes del modelo de sombreado. En lugar de eso es posible definir un determinado número de características de la superficie (el blanco mate es el valor de color por omisión).

Una declaración de superficie tiene la forma:

surface

{

[definiciones de superficie]

}

Por ejemplo, la siguiente declaración es una superficie roja con un destaque blanco, corresponde a la textura de "plástico" vista frecuentemente :

define shiny_red

texture

{

surface

{

ambient red, 0.2

diffuse red, 0.6

specular white, 0.8

microfacet Reitz 10

}

}

Las características de la superficie que pueden ser definidas son:

ambient	- Luz reflejada por la superficie

diffuse	- Luz reflejada en todas las direcciones

specular	- Cantidad y color de los reflejos

reflection	- Reflectividad de la superfície

transmission	- Cantidad y color de la luz refractada

microfacet	- Modelo de iluminación.

La ecuación de iluminación utilizada es (en términos algo simplificados):

L = ambient + diffuse + specular + reflected + transmitted,

o

L = Ka + Kd * (L1 + L2 + ...) + Ks * (L1 + L2 + ...) + Kr + Kt

Donde L1, L2, ... son las luces, Ka es el término de ambiente, Kd es el término difuso, Ks es el término "specular", Kr es el término reflexivo, y Kt el de transmisión (refringente). Cada uno de estos términos tienen un valor de escala y un valor de filtro (por omisión el filtro es blanco/claro si no se especifica).

Vea el archivo "colors.inc" para ver ejemplos de declaraciones de superficies, incluyendo: espejo, vidrio, brillante, y mate.

Para más detalles sobre modelos de iluminación, y la teoría de cómo el color es utilizado en las imágenes generadas por ordenador, corra (no camine) a su librería local y obtenga:

"Illumination and Color in Computer Generated Imagery"

Roy Hall, 1989

Springer Verlag

El código fuente en la parte trasera de ese libro fue la inspiración para el modelo de distribución "microfacet" implementado en Polyray.

Observe que en sí no es necesario especificar todos los componentes del color si no queremos. Si el color de una parte particular de la declaración de la superficie no está definido, entonces el valor del componente de "color" se examinará para ver si está declarado. Si es así, entonces ese color será utilizado como el filtro. Un ejemplo, la declaración anterior también se puede escribir como:

define shiny_red

texture

{

surface

{

color red

ambient 0.2

diffuse 0.6

specular white, 0.8

microfacet Reitz 10

}

}

2.4.3.1.1.1 Luz Ambiental

La luz ambiente es la luz expulsada por la superficie misma.

El formato de la declaración es:

ambient <color>, <escala>

ambient <escala>

Como siempre, el color será una vector RGB como <1.0, 0.7, 0.9>, o una etiqueta de color. La escala nos da la cantidad de contribución que el ambiente da a la cantidad total de luz procedente del pixel. Los valores de escala deberian radicar en el rango 0.0 -> 1.0

2.4.3.1.1.2 Luz Difusa

La iluminación difusa es la luz devuelta por la superficie bajo la estimulación de una fuente de luz.

El formato de la declaración es:

diffuse <color>, <escala>

diffuse <escala>

La única información utilizada para los cálculos difusos es el ángulo de incidencia de la luz en la superficie.

2.4.3.1.1.3 Brillos especulares

El formato de la declaración es:

specular <color>, <escala>

specular <escala>

El modelo utilizado para cálcular los brillos especulares por omisión es el modelo de Phong. Otros modelos se seleccionan mediante la declaración de distribución de Microfacetas.

2.4.3.1.1.4 Reflexiones

La luz reflejada es el color de cualquier objeto en la dirección reflejada calculada como la relación del ángulo de visión y el vector normal a la superficie.

El formato de la declaración es:

reflection <escala>

reflection <color>, <escala>

Típicamente, solamente el factor de escala se incluye en la declaración de reflejos, estos corresponden a todos los colores que se reflejan con intensidad proporcional a la escala. Se permite un filtro cromofotográfico en la definición de reflejo, permitiendo así la modificación del color que se está reflejando.

2.4.3.1.1.5 Transmisión de luz

La luz transmitida es el color de cualquier objeto en la dirección refractada calculada por la relación del ángulo de vista, el vector normal a la superficie, y el índice de refracción del material.

El formato de la declaración es:

transmit <escala>, <ior>

transmit <color>, <escala>, <ior>

Típicamente, solamente el factor de escala se incluye en la declaración de la transmisión de luz, estos corresponden a todos los colores que se transmiten con intensidad proporcional en la escala. Se permite un filtro cromofotográfico en la definición de transmisión, y esto permite la modificación del color que se transmite haciendo el filtro de transmisión diferente del color de la superficie misma.

Es posible tener superficies con colores muy diferentes al color más cercano que el ojo aparenta ver. ( Ver "gsphere. pi" como ejemplo, una esfera roja está situada en primer plano, una esfera verde y una esfera azul estan detrás. El brillo especular de la esfera roja se torna amarillo, y la luz azul está siendose transmitida a través de la esfera roja.)

Podemos ver un ejemplo más complejo en el archivo "lens.pi " en el que dos de las lentes convexas están alineadas frente al espectador. La vista amplificada de la parte de una rejilla de bolas coloreadas es totalmente diferente en la parte frontal de las lentes.

2.4.3.1.1.6 Distribución de Microfacetas.

La distribución de microfacetas es una función que determina como los brillos especulares son calculados para un objeto.

El formato de la declaración es:

microfacet <nombre_de_distribución> <ángulo_de_caida>

microfacet <ángulo_de_caida>

El nombre de distriución debe ser uno de los siguientes: Blinn, Cook, Gaussian, Phong, Reitz. El ángulo de caida es el ángulo en el que los brillos especulares se debilitan hasta un 50% de su intensidad máxima. (Contra más pequeño sea el ángulo de caida, más intenso será el brillo). Si el nombre de la microfaceta no se da, entonces se usa el modelo de Phong.

El ángulo de caida tiene que estar especificado en grados, comprendido entre el rango 0 a 45. El ángulo de caida corresponde a la aspereza de la superficie, contra más pequeño sea, más suave será ésta. Un gran ángulo de caida nos dará el mismo tipo de sombreado que el retornado por el sombreado difuso.

Nota: Como se planteó anterioemente, hechele un vistazo al libro. He encontrado valores de caida entre 5 y 10 grados que nos dan agradables brillitos. El uso del ángulo de caida se puede parecer un poco al de otros raytracers anteriores, que utilizaban normalmente un valor que definia la fuerza de una función coseno para definir la catidad de los brillos. Cuando usamos un valor cuantificador, a mayor sea éste, más pequeños serán los brillos. Si utilizando ángulos que sigan una pequeña ordenación, contra más pequeño sea el ángulo, más pequeño será el brillo.

2.4.3.1.2 Texturas de tipo "checker".

Éste tipo de textura tiene la forma:

texture

{

checker <textura1> , <textura2>

}

donde <texture1> y <texture2> son declaraciones de textura ( o constantes de textura).

Un estándar, en cierta medida, de un plano que tenga esta textura puede ser definido con las siguientes líneas:

// Fedinir una superficie roja mate

define rojo_mate

texture

{

surface

{

ambient red, 0.1

diffuse red, 0.5

}

}

// Definir una superficie azul mate

define azul_mate

texture

{

surface

{

ambient blue, 0.2

diffuse blue, 0.8

}

}

// Definir un plano que tiene una textura checker roja y azul

object

{

disc <0, 0.01, 0>, <0, 1, 0>, 5000

texture

{

checker rojo_mate, azul_mate

}

}

Para un ejemplo, ver el foichero spot0. pi. Este archivo tiene una esfera de textura checker rojo/azul, y un plano con textura checker negro/blanco.

Nota: Un problema que surge con planos con este tipo de texturas es el que surge debido al escalonamiento a grandes distancias. Una ayuda cuando surge el efecto de escalonamiento, es usar texturas checker más grandes (esto se realiza añadiendo un factor de escla a la textura), o asegurandose de que existe nivel bajo de luz a grandes distancias.

2.4.3.1.3 Texturas Hexagonales

La textura hexagonola está orientada en el plano x-z, y tiene la forma:

texture

{

hexagon <textura1>, <textura2>, <textura3>

}

Esta textura produce una especie de panel de abejas mediante el uso de las tres texturas en la declaración. Recuerde que este panel es con respecto al plano x-z, si lo quisieramos en una pared vertical, necesitariamos rotar la textura.

2.4.3.1.4 Superficies de Ruido

La complejidad y velocidad de renderizar las superficie de ruido subyace entre el modelo de sombreado estándar y las superficies especiales descritas más tarde. Es un intento de capturar un gran número de operaciones tridimensionales de añadir texturas estándar en una única declaración.

Una declaración de superficie de ruido tiene la forma:

texture

{

noise surface

{

[definición de la superficie de ruido]

}

}

Los posibles valores para la definición de la superficie de ruido son:

color <r,g,b>	El color básico de la superficie (usado si la función de ruido genera un valor no contenido en el mapa de color).

ambient <escala>	La cantidad de contribución de la luz ambiente.

diffuse <escala>	Contribución de la luz difusa.

specular <color>, <scala>	Cantidad y color de los brillos especulares, si el color no se da se usará en su lugar el color de cuerpo.

reflection <escala>	Reflectividad de la superficie.

transmission <escala>, <ior>	Cantidad de luz refractada.

microfacet <clase> <ángulo>	Modelo de iluminación especular (ver la descripción del modelo estándar de superficie).

color_map(<entradas_de_mapa>)	Define el mapa de color (ver la sección siguiente de definiciones de mapa de color para más detalles).

bump_scale <fexper>	La forma en la que el tamaño de las ondas (se suele emplear funciones senoidales para la gegeración de la superficie - el autor empleó la palabra "bumpiness" que hace referencia a baches y sacudidas, "meneo") afectan a la normal de la superficie.

frecuency <fexper>	Afecta a la longitude de las olas en las ondulaciones y ondas.

phase <fexper>	Afecta la fase de las ondulaciones y olas.

lookup_fn <índice>	Selecciona una función "lookup" predefinida.

normal_fn <índice>	Selecciona un modificador de la normal predefinido .

octaves <fexper>	Número de octavas de ruido a utilizar.

position_fn <índice>	La forma en la que el punto de intersección está siendo utilizado en el proceso de generar una textura de ruido.

position_scale <fexper>	La cantidad de contribución del valor de posición para la textura global.

turbulence <fexper>	La cantidad de contribución del ruido a la textura global.

La forma en la que el color final de la textura es decidido mediante el cálculo de un valor de punto flotante utilizando el siguiente fórmula general:

índice = lookup_fn(position scale * position_fn +

turbulence * noise3d(P, octaves))

El valor del índice que es calculado se usa entonces mejorar el color del mapa de colores. Este color final es utilizado para la luz ambiente, la luz difusa, los reflejos y los filtros de transmisión. Las funciones que están disponibles actualmente, con su correspondiente índice son:

Funciones de posición:

Índice	Efecto
1	El valor de x en el sistema de coordenadas del objeto
2	El valor de x en el sistema de coordenadas global
3	Distancia desde el eje z
4	Distancia desde el origen
5	Distancia desde el eje y (rnagos desde 0 a 1)

El valor por defecto es 0.0

Funciones Lookup:

Índice	Efecto
1	Función "sawtooth", el resultado oscila entre 0 y 1.
2	Función seno, el resultado oscila entre 0 y 1.
3	Función "rampa", el resultado oscila entre 0 y 1.

Por deffecto no se realiza ninguna modificación.

Las definiciones de estos números de función que tienen sentido son:

define position_plain	0

define position_ objectx	1

define position_worldx	2

define position_cylindrical	3

define position_spherical	4

define position_radial	5

define lookup_plain	0

define lookup_sawtooth	1

define lookup_sin	2

define lookup_ramp	3

Un ejemplo de una textura definida de esta forma es el típico marmol blanco:

define textura_marmol_blanco

{

noise surface

{

color	white

position_fn	position_objectx

lookup_fn	lookup_sawtooth

octaves	3

turbulence	3

ambient	0.2

diffuse	0.8

specular	0.3

microfacet	Reitz 5

color_map(	[0.0, 0.8, <1,1,1>, <0.6,0.6,0.6>]

[0.8, 1.0, <0.6,0.6,0.6>, <0.1,0.1,0.1>])

}

}

Además de la coloración, el grosor de la rigosidad de la superficie puede ser modificado seleccionando una función para alterar la normal. Las funciones para modificador las normales que dispone Polyray son:

Índice	Efecto
1	Realiza hoyos aleatorios en la superficie
2	Añade ondas a la superficie
3	Dota a la superifice de una apariencia dentada.

Por defecto no se realiza ninguna modificación.

Las definiciones que tienen sentido son:

define default_normal	0

define bump_normal	1

define ripple_normal	2

define dented_normal	3

Ver también el archivo "texture.txt" para una pequeña explicación adicional y ver algunas definiciones de texturas adicionales.

Archivos de ejemplo: textures. inc

2.4.3.1.5 Texturas estratificadas

Una textura estratificada o por capas es un modo de apilar una textura encima de otra. Si la textura de la parte superior posee algún tipo de transparencia, la capa de debajo estará sombreada, y su color será añadido al generado por la primera capa. Este proceso se repite a través de cada capa hasta que o bien se alcance una capa opaca o no existan más capas.

El formato de la declaración es:

texture

{

layered

{

<textura1>,

<textura2>,

...

<texturan>

}

}

La primera textura en la lista es la capa de textura superior, la última es la capa de textura de fondo. Como un ejemplo, las siguientes líneas definen una textura parecida al marmol que tiene un espejo en sus venas (refiriendose a las filigranas interiores que se asemejan a las venas del cuerpo). El modo en el que trabaja es utilizar un valor "alfa" en el mapa de color, en la medida en la que el color de la vena se transforma en negro, el valor "alfa" se incrementa hacia 1.0. La capa de fondo en este caso es un espejo, y solamente aparece cuando estamos mirando la parte venosa de la textura.

// Fichero de ejemplo de Polyray

// Una textura de gradiente con valores variables de "alfa"

//

viewpoint

{

from <0, 2, -10>

at < 0,0,0 >

up< 0,1,0 >

angle 35

resolutiin 80, 80

aspect 1

}

include "colors.inc"

background midnightblue

light <10, 7,- 5>

define position_objectx	1

define lookup_sawtooth	1

// Realizar una variante en del marmol blanco que tiene transparencia en sus venas

define marmol_blanco_alfa

texture

{

noise surface

{

color	white

position_fn	position_objectx

lookup_fn	lookup_sawtooth

octaves	3

turbulence	3

ambient	0.3

diffuse	0.8

specular	0.3

microfacet	Reitz 5

color_map(	[ 0.0, 0.2, white, 0, white, 0]

[ 0.2, 0.5, white, 0, black, 0.2]

[ 0.6, 1.0, black, 0.2, blck, 1])

}

}

// Ahora construimos la textura por capas basandones en la anteriormente

// definida, así como la textura de "espejo" definida en "colors.inc"

define marmol_espejo

texture

{

layered

{

marmol_blanco_alfa,

mirror

}

}

// Realiza una esfera que tiene el la textura por capas

object

{

sphere < 0, 0, 0>, 2

marmol_espejo

}

// Añade un piso variado, de modo que vemos algo reflejado en la parte

// correspondiente de la esfera.

object

{

disc <0, -2.005, 0>, <0,1,0>, 10

texture

{

checker matte_white, matte_black

}

}

Ficheros ejemplo: layer1.pi, layer2. pi

2.4.3.2 Texturas Funcionales

Las texturas más generales en Polyray son las texturas funcionales. Estas texturas son evaluadas en en tiempo de ejecución basandose en las expresiones dadas en los componentes del modelo de iluminación. La sintaxis general para una superficie utilizando una textura funcional es:

special surface

{

[declaración de superficie]

}

Además a los componentes generalmente definidos en una declaración de superficie, es posible definir una función que desvie la normal, y un "cuerpo" de color que será usado como el filtro cromofotográfico para la luz ambiente, la difusa, etc., componentes de la declaración de superficie... El formato de las dos declaraciones son:

color <vexper>

y

normal <vexper>

Un ejemplo de como una textura funcional puede ser definido es:

define desplazamineto_senoidal_del_color

(sin(3.14 * fmod( x * y * z, 1) + otheta)+ 1) / 2

define color_senoidal

<desplazamineto_senoidal_del_color, 0, 1 - desplazamineto_senoidal_del_color>

define textura_senoidal_xyz

texture

{

special surface

{

color	color_senoidal

ambient	0.2

diffuse	0.7

specular	white, 0.2

microfacet	Reitz 10

}

}

En este ejemplo, el color de la superficie está definido basadose en la ubicación del punto de intersección utilizando el vector definido como "color_senoidal".

Archivos ejemplo: cossph.pi, cwheel. pi.

2.4.3.2.1 Mapas de imagenes.

Un tipo de coloreado que se puede usar involucra el uso de una imagen existente proyectada hacia una superficie. Hay cuatro tipos de proyección , plana, cilíndrica, esferica, y de entorno. Los archivos de entrada que se pueden utilizar como mapas de imagen son ficheros TGA de 8,16, 24, y 32 bit, bien sin comprimir, bien con comprensión RLE, y ya sean en escala de grises o en color.

La declaración de un mapa de imagen es:

image("fichero_imagen.tga")

Típicamente, una imagen será asociada con una variable a través de una definición como:

define mi_imagen image("imagen.tga")

La imagen se proyecta hacia un objeto gracias a una "proyección". Los cuatro tipos de proyección se declaran de la siguiente forma:

planar_imagemap( <imagen>, <coordenadas> [, repetir])

cylindrical_imagemap( <imagen>, <coordenadas> [, repetir])

spherical_imagemap( <imagen>, <coordenadas>)

environment_map(environment( <imagen1>, <imagen2>, <imagen3>,

<imagen4>, <imagen5>, <imagen6> ))

La proyección plana, proyecta la imagen "raster" completa en el plano XZ, en las coordenadas 0< x< 1, 0< z< 1. El valor de vector mostrado como "coordenadas" se utiliza para selecciona un color multiplicando el valor x por la cantidad de columnas, y el valor z por la cantidad de filas.

El color que aparece en dicha posición del "raster" se retornará como resultado. Si aparece un valor de repetición (repetir) se rellenará toda la superficie, repitiendo entre cada valor de x y/o de z.

La proyección cilíndrica envuelve la imagen sobre un cilindro que tiene un extremo en el origen y el otro en el punto < 0, 1, 0>. Si aparece un valor "repetir", entonces la imagen se repetirá a lo largo de eje OY, si no se diera ninguno, entonces cualquier parte del objeto que no este recubierto por la imagen serán puesto con el color de pixel (0, 0).

La proyección esferica envuelve la imagen sobre una esfera centrada en el origen. La costura de fondo y de la parte superior (recuerde que la imagen forma un plano) están dobladas en los polos norte y sur respectivamente. Los bordes izquierdo y derecho de la imagen estan unidos sobre el eje OX.

El mapa de entorno envuelve seis imágenes alrededor de un punto. Este método es un modo estándar de fingir reflejos envolviendo las imágenes que serían vistas desde un punto dentro de un objeto alrededor de dicho objeto. Una muestra de esta técnica se puede observar al renderizar el ficehro "room1.pi" (que genera las imágenes), después deberemos renderizar "room0.pi" (que envuelve las imágenes alrededor de una esfera).

Los siguientes son un par de ejemplos de objetos y texturas que pueden hacer uso de mapas de imagen:

define hivolt_image	image("hivolt.tga")

define hivolt_tex

texture

{

special surface

{

color	cylindrical_imagemap(hivolt_image, P, 1)

ambient	0.9

diffuse	0.1

}

scale < 1, 2, 1>

translate <0,- 1, 0>

}

object

{

cylinder <0,- 1, 0>,<0, 1, 0>, 3

hivolt_tex

}

y

define disc_image	image("prueba.tga")

define disc_tex

texture

{

special surface

{

color	planar_imagemap(disc_image, P)

ambient	0.9

diffuse	0.1

}

translate <-0.5, 0, -0.5>

scale <7*4/3, 1, 7>

rotate <90, 0, 0>

}

object

{

disc <0, 0, 0>, <0, 0, 1>, 6

u_steps 10

disc_tex

}

2.5 Comentarios.

Se permiten los comentarios de línea y tienen el siguiente formato:

// [cualquier texto hasta final de la línea]

Tan pronto como se detecten los dos caracteres "//", se ignorará el resto de la línea ya que se considerada un comentario.

2.6 Apoyo de Animación.

Una animación se genera produciendo una serie de fotogramas, numerados desde 0 a algún valor final. Las declaraciones en Polyray que permiten la generación de imágenes Targa múltiples son:

total_frames <valor>	El número total de fotogramas en la animación.

start_frame <valor>	El valor del primer fotograma que se produce.

end_frame <valor>	El valor del último fotograma que se producirá.

outfile "nombre"

outfile <nombre>	Polyray añadirá el número de fotograma a este nombre para generar los distintos archivos Targa.

Los valores de "total_frames", "start_frame", y "end_frame", así como el valor del fotograma actual, "frame", se pueden utilizar en expresiones aritméticas en el archivo fuente. Observe que estas declaraciones deberian aparecer antes del uso de: total_frames, start_frame, end_frame, o frame como parte de una expresión. Por lo general pongo estas declaraciones declaraciones en la parte superior del archivo.

Precaución: Si la nombre para "outfile" es más largo de 5 caracteres, los número de fotograma de tres dígitos que son añadidoa serán truncados por el DOS. Asegúrese de que esta cadena sea cortamente suficientemente o terminará sobreescribiendo los archivos de imagen.

Archivos de ejemplo: whirl.pi, plane.pi, squish.pi

2.7 Procesamiento Condicional.

En apoyo para la generación de animaciones (y también porque a veces necesitamos conmutar entre varios atributos en la definición de los objetos), Polyray nos provee de un cierto procesamiento condicional limitado. La sintaxis es:

if (cexper)

{

[ declaraciones de objetos, luces, etc ...]

}

else

{

[ declaraciones de otros objetos, luces, etc ...]

}

El archivo de ejemplo "rsphere.pi" muestra como se puede utilizar esta técnica para modificar el color de una esfera en movimiento.

El uso de declaraciones condicionales está limitado esclusivamente al nivel superior del fichero de datos. No podremos usar una sentencia condicional dentro de la declaración de un objeto o textura. p. e.

object

{

if (foo == 42)

{

sphere <0, 0, 0>, 4

}

else

{

disc <0, 0, 0>,< 0, 1, 0>, 4

}

}

No sería válido, mientras que:

if (foo == 42)

{

object

{

sphere <0, 0, 0>, 4

}

}

else

{

object

{

disc <0, 0,0>,< 0, 1, 0>, 4

}

}

o

if (foo == 42)

object {sphere <0,0,0>, 4}

else

if (foo == 12)

{

object { torus 3.0, 1.0, <0,0,0>, <0,1,0> }

object { cylinder <0,-1,0>, <0,1,0>, 0.5 }

}

else

object { disc <0,0,0>, <0,1,0>, 4 }

Serían válidas.

Nota: Las llaves "{}" son requeridas si hay declaraciones múltiples dentro de las sentencias condicionales, y no los son si solo existe una única declaración.

2.8 Inclusión de archivos

Para permitir dividir un archivo fuente en varios archivos (así como permitir el uso de librerias), es posible dirigir a Polyray para que procese otro archivo. La sintaxis es:

include "nombre de fichero"

Cuidado con intentar utilizar "# incluye... " fallará ya que Polyray lo considerará como un comentario.

2.9 Flujo de archivos.

Las ocurrencias imprevistas, como fallos en la alimentación del equipo, o los mismos compañeros de cuarto que pulsan la tecla de reset para realizar alguno otra labor, nos es posible especificar cuan a menudo el archivo de salida serán salvado al disco. El valor por omisión es esperar hasta que el fichero completo se procese antes de escribirlo en disco (que es algo más rápido pero perderemos todo el tabajo si ocurre algún error). El formato de la declaración es:

file_flush xxx

El número xxx indica el número máximo de pixels que serán escritos antes de que algun tipo de error ocurra. Este valor puede ser tan bajo como 1, forzandose la escritura después de la generación de cada pixel (solo para el típico paranoico).

3. Formatos de archivo.

3.1 Archivos de salida.

Actualmente se soporta el formato TGA como archivo de salida ya sea en 8, 16, 24, y 32 / bits por pixel, ya sea sin comprimir o comprimido mediante el algoritmo RLE (tipos 2, 3, y 10). Si no estuviera definido el archivo de salida en la opción "-o" de la línea de comandos, se utilizará el archivo "out.tga". La opción de la línea de comandos -u especifica que no se debe realizar ninguna compresión en el archivo de salida.

El formato de salida omisión es un RLE comprimió en 16 bits/pixel. Este formato usa 5 bits para cada componente de un color RGB. La razón para elegir este formato es que muy pocas tarjetas gráficas pueden garantizar 24 bits/pixel encontrando este formato los límites típicos 2de las tajetas gráficas de 8 y 15 bits/pixel. Si su hardware puede mostrar más que 32 K colores entonces debería establecer los switches de la línea de comandos para que pueda generar ficheros Targa de 24 o 32 bits/pixel. Si solo estuviera interesado en imagenes de escala de grises use el fotmato TGA de 8 bits/pixel.

4. Algoritmos.

4.1 Procesando expresiones polinomiales.

El programa en su forma actual permite la definición de superficies polinomiales de grado inferior a 33, pero debido a la inestabilidad numérica es aconsejable usar valores inferiores a 10 y a ser posible inferiores a 6.

El modo en que la expresión polinomial se procesa y se manipula se muestra en los siguientes pasos:

1) Se analiza léxicamente la expresión tal como se recoge del archivo de entrada. El analizador de léxico PC-YACC (parser) que se utiliza para procesar el archivo de entrada crea un árbol con la expresión que se ha leido. El formato para la expresiones permitidas será descrito en sección 4.1. 2.

2) Se expande la expresión en una suma simple de subexpresiones. Después de que se construya el árbol, la expresión se expande de modo que se queda en su forma expandida. (p. e. (x+1)^2 será reescrita como x^2+2*x+1.) Las reglas para realizar esto son explicadas en la sección 4.1.3.

2

3) Determinar cual es el orden del polinomio que es representado por la expresión. Cada término en la expresión expandida es examinado para ver cual es el mayor orden de x, y, y z que se utiliza. Esto determina el orden N del polinomio. A partir de este valor se determina la cantidad de términos posibles para dicho orden.

4) Crear una matriz de coeficientes para la ecuación general de tres variables del polinomio de orden N. Hay un total de (N+1) * (N+2) * (N+3) / 6 términos en la ecuación general. Los valores de cada uno de los coeficientes en la expresión expandida son entonces sustituidos en la matriz de coeficientes.

Observe que el almacenamiento de expresiones no es particularmente eficiente para valores muy altos de N.

4.1.1 Ejemplo de una ecuación de representación.

Como un ejemplo de como se expande dicho árbol, dada la entrada:

(x+y) * (1-x-z) + (x-z)^2

La representación expandida es:

-1*x*y + -3*x*z + x + -1*y*z + y + z^2

Este es un polinomio de orden 2, y la matriz de coeficientes es:

0 0 1 -1 -3 -1 1 1 0 0

4.1.2 Sintaxis de Fórmulas permitidas.

La palabra clave aquí es expresiones algebráicas "simples". Las únicas variables permitidas son "x", "y", y "z" ( y solamente minúsculas). Las constantes son números de punto flotante. Las operaciones permitidas entre constantes y los tres símbolos variables son: adición, substracción, multiplicación, negación unaria, y exponenciación por una potencia entera positiva. Ejemplos de expresiones que pueden ser procesados son:

x^2 + y -42

(1+x+y+z)^2 * 2 * (x-y) * (z- x*(133-z^2 ))

27*x-y*42*y^2

(x^2+y^2+z^2+3) - (x*y-x^2) * z^2

Ejemplos de expresiones que no pueden ser procesados son:

x / y

x^0. 5+ y

x^- 2

4.1.3 Reglas para procesar fórmulas.

Solo hay algunas pocas reglas necesarias para simplificar una expresión polinomial al punto en que éstas pueden ser insertadas fácilmente en una matriz de coeficientes. Aparecen debajo, con las letras A, B, C, y D asoziadas a una subexpresión arbitraria. Las reglas utilizadas para simplificar una expresión son:

Adición:

No se necesita ninguna simplificación para el término: A+ B

Substracción:

A - B ---> A + (- B)

Negación unaria:

-(A * B) ---> (-A * B)

-(A+ B) ---> (-A+ -B)

Multiplicación:

A*(B+C) ---> A*B + A*C

(A+B)*C ---> A*C + B*C

(A+B)*(C+D) ---> A*C + A*D + B*C + B*D

Exponenciacion:

(A*B)^n ---> A^n * B^n

(A+B)^n ---> C(n,0) * A^n + C(n,1) * A^(n-1) * B +... C(n, n-1) * A * B^(n-1) + C(n, n) * B^n {C(n, r) es el coeficiente binomial}

Cada uno de las subexpresiones es cada vez más simple hasta que cada término en la expresión llega a la forma: const * x^i * y^j * z^k.

4.2 Procesando superficies funcionales arbitrarias

El algoritmo básico para determinar un punto de intersección utilizando matemáticas de intervalo es bastante simple:

1) Dar un rango de valores permitidos para el parámetro de rayo T, un se calcula entonces un rango de valores de la función.

2) Si el rango no incluye 0 entonces no hay intersección.

3) Si el rango incluye 0, entonces:

A) El rango de valores de la derivada de la función se calcula para los valores permitidos del parámetro de rayo T.

B) Si el rango de valores de la derivada incluye 0, entonces el intervalo para T es bisecado y procesamos cada subintervalo comenzando de nuevo con el paso 1.

C) Si el rango de valores de la derivada no incluye 0, entonces sabemos que hay exactamente una solución de la función en el intervalo actual. Una solucionador de raices estándar que usa el método "regula-falsi" se llama para encontrar la raíz.

Por supuesto este tema es mucho más profundo...

4.2.1 Coordenadas esféricas.

Para trazar las fucniones que son definidas en función de coordenadas esféricas debemos utilizar las siguientes sustituciones:

r	= sqrt(x^2 + y^2 + z^2 ),

theta	= atan(y/x),

phi	= atan(sqrt(x^2 + y^2) / z)

Ficheros ejemplo: sectorl. pi, zonal.pi

4.3 Generación de ruido Tridimensional.

El modo en que Polyray genera valores de ruido desde las entradas de un vector sigue los siguientes pasos:

1) La parte entera de los valores x, y, y z del vector son determinados.

2) Los ocho puntos enteros circundantes al vector de entrada son determinados.

3) Una especie de función troceadora (descrita más abajo ) se aplica a los puntos enteros que rodean al vector de entrada, resultando en ocho números aleatorios.

4) Un número final se determinada sopesando los valores asociados con los puntos que los rodean con la distancia del vector de entrada a aquellos puntos.

El resultado de esto es que cada punto en un entramado tiene un valor aleatorio, pero cada valor fraccional dentro de un cubo unitario en dicho entramado se relaciona con los puntos que lo rodean.

La función "troceadora" que utilizo coge los 10 bits inferiores de la parte entera del vector de entrada, obteniendo de ellos un número único, entonces empaqueta este valor gracias a una serie de adiciones, multiplicaciones, y varios métodos para obtener un valor único. El algoritmo es:

K =	( ( x & 0x03ff) << 20) |

( ( y & 0x03ff) << 10) |

( z & 0x03ff);

Kt = 0;

for (i=0; i<mult_table_size;++i)

Kt = ((Kt + K) * mult_table[i]) % HASH_SIZE;

result = (Flt) Kt / (Flt) (HASH_SIZE - 1);

El número y valor de las entradas en "mult_table" fue elegido aleatoriamente, al igual que lo fue el valor HASH SIZE. No tengo forma de determinar si el resultado de esta función "troceadora" realmente esparce uniformemente, sin embargo los resultados visuales debido a su uso son bastante aceptables.

4.4 El algoritmo "Marching Cubes".

El algoritmo "Marching Cubes" situa un entramado sobre el espacio tridimensional sobre que se colaca el objeto. Poniendo a través de cada subcubo del entramado y buscando los lugares donde superficie atraviesa el subcubo, un buen acierto se puede generar para la cubierta poligonal de la superficie. Este algoritmo es utilizado para rastrear la burbujas convertidoras (blobs), las funciones polinomiales, y las funciones implícitas.

En la medida en que cada uno de los cubos es procesado, cada vértice del cubo es probado para ver si está dentro del objeto "tipo hot", o fuera de el objeto "tipo cold". Existen un total de 2^8 = 256 combinaciones posibles de vértices de tipo hot y cold.

El procesamiento de cada subcubo en el entramado se recoge en estos pasos:

- Cada uno de los 8 vértices del cubo corresponden a un bit de un entero sin signo (unsigned char). Si el vértice es de topo hot entonces el bit es puesto a 1, si es de tipo cold se establece a 0.

- Utilizando la teoria combinacional y la teoria de grupos, es posible clasificar, bajo el grupo de rotaciones sólidas de un cubo, cada una de las 256 posibilidades de uno de los 23 únicos casos básicos. (Podemos realmente bajar a 14, pero esto habría complicado algunas partes del algoritmo).

- Cada uno de los casos básicos tiene una entrada en una tabla de triángulos que separa los vértices de tipo hot de los vértices de tipo cold del cubo original.

- Utilizando las inversas de las rotaciones que situaron el cubo en el caso básico, los triángulos son rotados para separar los vétices hot y cold del cubo original.

- La cantidad de vértices hot y la cantidad de vértices cold que son separados por cada triángulo es examinada para ver cuánto hay que desplaazr el triángulo hacia arriba o hacia abajo. Esta es una interpolación lineal que ayuda a mantener los triángulos cerca de la superficie real.

- Ahora que los triángulos son conocidos y en aproximadamente el lugar adecuado, la rutina de conversión que rastrea la normal es llamada para cada triángulo.

El mayor inconveniente de este algoritmo es que la cantidad de evaluciones aumenta para cada cubo si se aumenta la resolución dle entramado. Por ejemplo, si u_steps tiene un valor de 20 y v_steps tiene otro de 20 (El valor por omisión), entonces 20 x 20 x 20 = 8.000 subcubos serán analizados. Si fueramos a aumentar la resolución en un factor de 5, serían entonces untotal de 100 x100 x100 = 1.000.000 de subcubos analizados.

Otro problema es el del escalonamiento. Si la superficie es muy compleja y/o contiene muchos caracteres distintivos pequeños, y la cantidad de pasos a lo largo de los ejes es insuficiente para determinar adecuadamente "el dentro y el afuera", entonces grandes porciones de la superficie pueden desaparecer. La solución es aumentar los tamaños de paso, o tracear, cada opción aumentará el tiempo de proceso.

Nota: Cuando construí la tabla de triángulos, realicé la suposición de que si hay dos modos de dividir los vértices hot de los cold entonces un vértice hot se conectarían siempre a otro hot. Un ejemplo de esta opción es cuando las vértices: (0, 0, 0), (1, 0, 0), (0, 1, 1), y (1, 1, 1) son todos hot y el resto cold.

5. Notas del traductor.

Esta traducción es libre y puede tener algunas modificaciones sobre las expresiones originales del idioma inglés. Las expresiones que eran virtualmente imposibles de traducir las he utilizado tal cual.

Huelva, 27 de Febrero de 1.994

Para todos los infoadictos ...

Huelva, 19 de Abril de 1.995

El resto de los puntos que quedan del manual del Polyray no los he traducido. Ya que realmente no son importantes para aprender a manejar este programa. Para aquellos que quieran verlos siempre tendran a su disposición el manual original en inglés.

Estos puntos tratan de algunos temas diversos entre los que se incluyen una breve revisión historica de las distintas versiones de Polyray, la bibliografia (virtualmente es imposible conseguirla), los distintos arhivos de ejemplo que vienen con Polyray, y la gramática para el parsec PC-YACC (realmente no sé porque el autor a puesto esto, puede que como alguna referencia de programación).

Espero que esta traducción libre del manual sirva de utilidad para todos los hablantes de nuestra grandiosa lengua que deseen al igual que yo adentrarse en este fascinante mundo de la infografía casera, hecho que hasta hace bien poco solo era posible para los susodichos anglosajones.

Recomiendo que el que pueda (y sepa un poco de inglés) adquiera el libro "Adventures in Raytracing" de un tal Alfonso Hermida, es bastante bueno, y sirve como una ampliación del manual que ya de por sí es bastante escueto. Además viene con una tool tipo CAD para diseñar mundos para Polyray (tambien para el POV) bajo Windows o DOS denominada POVCAD (aunque es un poquillo lenta).

Saludos,

Miguel Angel Díaz Mariscal